diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/Commands.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/Commands.java new file mode 100644 index 000000000..a81a3ffe7 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/Commands.java @@ -0,0 +1,36 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +public enum Commands { + + CREATECOMMAND("create"), + SIZECOMMAND("size"), + COMMITCOMMAND("commit"), + ROLLBACKCOMMAND("rollback"), + DROPCOMMAND("drop"), + USECOMMAND("use"), + SHOWCOMMAND("show"), + PUTCOMMAND("put"), + GETCOMMAND("get"), + REMOVECOMMAND("remove"), + LISTCOMMAND("list"), + EXITCOMMAND("exit"); + + + private String value; + private Commands(String word) { + value = word; + } + + public static Commands getCommand(String word) throws IllegalArgumentException { + for (Commands command : Commands.values()) { + if (command.getValue().equals(word)) { + return command; + } + } + throw new IllegalArgumentException(word + " - unknown command"); + } + + public String getValue() { + return value; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/HandlerException.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/HandlerException.java new file mode 100644 index 000000000..b0a8d45f8 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/HandlerException.java @@ -0,0 +1,15 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +public class HandlerException { + public static void handler(String message, Throwable cause) { + System.err.println(message + ". " + cause.getMessage()); + System.exit(1); + } + public static void handler(Throwable cause) { + System.err.println(cause.getMessage()); + System.exit(1); + } + +} + + diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/InteractiveParse.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/InteractiveParse.java new file mode 100644 index 000000000..2fe7ae336 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/InteractiveParse.java @@ -0,0 +1,40 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.commands.Commands; + +import java.util.NoSuchElementException; +import java.util.Scanner; + +public class InteractiveParse { + public static void parse(MyTableProvider directory) { + Scanner in = new Scanner(System.in); + try { + while (true) { + System.out.print("$ "); + String s; + s = in.nextLine(); + s = s.trim(); + String[] current = s.split("\\s+"); + for (int i = 0; i < current.length; ++i) { + current[i].trim(); + } + try { + Commands command = Commands.fromString(current); + command.execute(directory); + } catch (NoSuchElementException e) { + System.err.println(e.getMessage()); + } + } + } catch (IllegalMonitorStateException e) { + in.close(); + System.out.println("Goodbye"); + System.exit(0); + } catch (NoSuchElementException e) { + System.err.println(e.getMessage()); + } catch (Exception e) { + in.close(); + HandlerException.handler(e); + } + in.close(); + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTable.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTable.java new file mode 100644 index 000000000..214774e97 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTable.java @@ -0,0 +1,316 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +import ru.fizteh.fivt.storage.strings.Table; + +import java.io.*; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MyTable implements Table { + + private Path mainDir; + private Map> databases; + private static Map> changes = new HashMap<>(); + private int numberChanges = 0; + + public static final int COUNT_OBJECT = 16; + public static final int COMMON_CONSTANT_INDEX = 100; + public static final String ENCODING = "UTF-8"; + public static final String SUF_DIR = ".dir"; + public static final String SUF_FILE = ".dat"; + + public MyTable(File tableDir) { + try { + databases = new HashMap<>(); + mainDir = tableDir.toPath(); + + for (int i = 0; i < COUNT_OBJECT; i++) { + File subDir = new File(tableDir, i + SUF_DIR); + for (int j = 0; j < COUNT_OBJECT; j++) { + File dbFile = new File(subDir, j + SUF_FILE); + if (dbFile.exists()) { + String adds = index(i, j); + databases.put(adds, new HashMap()); + readFromFile(dbFile, databases.get(adds)); + } + } + } + } catch (IllegalArgumentException e) { + HandlerException.handler(e); + } + } + + public boolean containsKey(String adds) { + return databases.containsKey(adds); + } + + @Override + public String getName() { + return mainDir.toString(); + }; + + private String pathname(String key) { + int hashCode = Math.abs(key.hashCode()); + int dir = hashCode % COUNT_OBJECT; + int file = hashCode / COUNT_OBJECT % COUNT_OBJECT; + return index(dir, file); + } + + private String index(int i, int j) { + return Integer.toString(i * COMMON_CONSTANT_INDEX + j); + } + + @Override + public String get(String key) throws IllegalArgumentException { + if (key != null) { + String adds = pathname(key); + return databases.get(adds).get(key); + } else { + throw new IllegalArgumentException("get: Haven't key. "); + } + } + + @Override + public String put(String key, String value) { + if ((key != null) || (value != null)) { + String adds = pathname(key); + if (!databases.containsKey(adds)) { + databases.put(adds, new HashMap()); + } + + String oldValue = databases.get(adds).get(key); + databases.get(adds).put(key, value); + numberChanges++; + changes.put(numberChanges, new ArrayList()); + changes.get(numberChanges).add("put"); + changes.get(numberChanges).add(key); + changes.get(numberChanges).add(value); + if (oldValue == null) { + changes.get(numberChanges).add("new"); + } else { + changes.get(numberChanges).add(oldValue); + } + return oldValue; + } else { + throw new IllegalArgumentException("put: Haven't key or value. "); + } + } + + @Override + public String remove(String key) { + if (key != null) { + String adds = pathname(key); + if (!databases.containsKey(adds)) { + return null; + } else { + String oldValue = databases.get(adds).get(key); + databases.get(adds).remove(key); + numberChanges++; + changes.put(numberChanges, new ArrayList()); + changes.get(numberChanges).add("remove"); + changes.get(numberChanges).add(key); + changes.get(numberChanges).add(oldValue); + return oldValue; + } + } else { + throw new IllegalArgumentException("get: Haven't key. "); + } + } + + @Override + public int size() { + int answer = 0; + for (int i = 0; i < COUNT_OBJECT; i++) { + for (int j = 0; j < COUNT_OBJECT; j++) { + String adds = index(i, j); + if (databases.containsKey(adds)) { + answer += databases.get(adds).size(); + } + } + } + return answer; + } + + @Override + public int commit() { + numberChanges = 0; + changes = new HashMap<>(); + + int count = 0; + for (int i = 0; i < COUNT_OBJECT; i++) { + for (int j = 0; j < COUNT_OBJECT; j++) { + String adds = index(i, j); + if (databases.containsKey(adds)) { + File directory = new File(mainDir.toString(), i + SUF_DIR); + if (!directory.exists()) { + if (!directory.mkdir()) { + throw new UnsupportedOperationException("ParserCommands.commandsExecution.put:" + + " Unable to create directories in working catalog"); + } + } + File dataBaseOld = new File(directory, j + SUF_FILE); + if (dataBaseOld.exists()) { + try { + Files.delete(dataBaseOld.toPath()); + } catch (IOException e) { + throw new RuntimeException("writeInFile: Can't overwrite file"); + } + } + + if (!dataBaseOld.exists()) { + try { + if (!dataBaseOld.createNewFile()) { + throw new IOException(); + } + } catch (IOException | NullPointerException e) { + throw new UnsupportedOperationException("ParserCommands.commandsExecution.put:" + + " Unable to create database files in working catalog"); + } + } + try (RandomAccessFile dbFile = new RandomAccessFile(dataBaseOld, "rw")) { + for (Map.Entry current : databases.get(adds).entrySet()) { + count++; + writeNext(dbFile, current.getKey()); + writeNext(dbFile, current.getValue()); + } + } catch (FileNotFoundException e) { + throw new RuntimeException("writeInFile: File not found"); + } catch (IOException e) { + throw new RuntimeException("writeInFile: Can't write to file.", e); + } + + if (databases.get(adds).size() == 0) { + File subDir = new File(mainDir.toString(), i + SUF_DIR); + File dbFile = new File(subDir, j + SUF_FILE); + try { + if (dbFile.exists()) { + Files.delete(dbFile.toPath()); + } + } catch (IOException e) { + throw new IllegalStateException("remove: " + + "Cannot delete database file. ", e); + } + databases.remove(adds); + + int k = 0; + for (int file = 0; file < COUNT_OBJECT; file++) { + String variableAdds = index(i, file); + if (databases.containsKey(variableAdds)) { + k++; + } + } + if (k == 0) { + try { + Files.delete(subDir.toPath()); + } catch (DirectoryNotEmptyException e) { + throw new IllegalStateException("remove: Cannot remove table subdirectory. " + + "Redundant files", e); + } catch (IOException e) { + throw new IllegalStateException("remove: " + + "Cannot delete database subdirectory", e); + } + } + } + } + } + } + return count; + + } + + private void writeNext(RandomAccessFile dbFile, String word) throws IOException { + try { + dbFile.writeInt(word.getBytes(ENCODING).length); + dbFile.write(word.getBytes(ENCODING)); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("writeNext: Don't supported encoding " + ENCODING + ". "); + } catch (IOException e) { + throw new RuntimeException("writeNext: Can't write to database. ", e); + } + } + public void readFromFile(File dbFileName, Map data) throws IllegalArgumentException { + try (RandomAccessFile file = new RandomAccessFile(dbFileName.toString(), "r")) { + + if (file.length() > 0) { + while (file.getFilePointer() < file.length()) { + String key = readNext(file); + String value = readNext(file); + if (data.containsKey(key)) { + throw new IllegalArgumentException("readFromFile: Two same keys in database file"); + } + data.put(key, value); + } + } + } catch (UnsupportedEncodingException | IllegalArgumentException | FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(" readFromFile: Problems with reading from database file " + e.toString()); + } catch (Exception e) { + throw new RuntimeException("readFromFile: ", e); + } + } + + + private String readNext(RandomAccessFile dbFile) throws IOException { + try { + int wordLength = dbFile.readInt(); + byte[] word = new byte[wordLength]; + dbFile.read(word, 0, wordLength); + return new String(word, ENCODING); + } catch (UnsupportedEncodingException e) { + throw new UnsupportedEncodingException("readNext: UTF-8 encoding is not supported"); + } catch (IOException e) { + throw new IOException(" readNext: Can't read from database " + e.toString()); + } + } + + + @Override + public int rollback() { + int count = 0; + Map> saveChanges = changes; + for (int i = saveChanges.size(); i > 0; i--) { + String[] com = new String[saveChanges.get(i).size()]; + com = saveChanges.get(i).toArray(com); + String message; + if (com[0].equals("put")) { + if (com[3].equals("new")) { + message = remove(com[1]); + } else { + message = put(com[1], com[3]); + } + } + if (com[0].equals("remove")) { + put(com[1], com[2]); + } + count++; + } + numberChanges = 0; + changes = new HashMap<>(); + return count; + } + + @Override + public List list() { + List listKey = new ArrayList<>(); + for (int i = 0; i < COUNT_OBJECT; i++) { + for (int j = 0; j < COUNT_OBJECT; j++) { + String adds = index(i, j); + if (databases.containsKey(adds)) { + for (String key : databases.get(adds).keySet()) { + listKey.add(key); + } + } + } + } return listKey; + } + + public int unsavedChanges() { + return numberChanges; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTableProvider.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTableProvider.java new file mode 100644 index 000000000..25480c37e --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTableProvider.java @@ -0,0 +1,145 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +import ru.fizteh.fivt.storage.strings.Table; +import ru.fizteh.fivt.storage.strings.TableProvider; + +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + + +public class MyTableProvider implements TableProvider { + + private HashMap tables; + private String using; + private File parentDirectory; + + public static final int COUNT_OBJECT = 16; + public static final int COMMON_CONSTANT_INDEX = 100; + public static final String SUF_DIR = ".dir"; + public static final String SUF_FILE = ".dat"; + + + public MyTableProvider(String path) { + parentDirectory = new File(path); + using = null; + tables = new HashMap<>(); + + try { + if (path == null) { + throw new NullPointerException(" Wrong path"); + } + if (!Files.exists(parentDirectory.toPath()) && !parentDirectory.mkdir()) { + throw new IllegalArgumentException(" Cannot create working directory"); + } + if (!parentDirectory.isDirectory()) { + throw new IllegalArgumentException("" + parentDirectory.toString() + + " is not a directory"); + } + for (String childName : parentDirectory.list()) { + File childDirectory = new File(parentDirectory, childName); + if (childDirectory.isDirectory()) { + tables.put(childName, new MyTable(childDirectory)); + } else { + throw new IllegalArgumentException(childName + + " from databases directory is not a directory"); + } + } + } catch (IllegalArgumentException e) { + HandlerException.handler(e); + } + } + + @Override + public Table getTable(String name) { + return tables.get(name); + } + + @Override + public Table createTable(String name) { + if (name == null) { + throw new IllegalArgumentException("createTable: " + + "Invalid name. "); + } + if (tables.containsKey(name)) { + return null; + } else { + File newTable = new File(parentDirectory, name); + if (!newTable.mkdir()) { + throw new UnsupportedOperationException("createTable: " + + "Unable to create working directory for new table. "); + } + tables.put(name, new MyTable(newTable)); + return tables.get(name); + } + } + + @Override + public void removeTable(String name) { + if (name == null) { + throw new IllegalArgumentException("removeTable: " + + "Invalid name. "); + } + if (tables.containsKey(name)) { + File table = new File(parentDirectory, name); + for (int i = 0; i < COUNT_OBJECT; i++) { + File subDir = new File(table, i + SUF_DIR); + for (int j = 0; j < COUNT_OBJECT; j++) { + String adds = Integer.toString(i * COMMON_CONSTANT_INDEX + j); + if (tables.get(name).containsKey(adds)) { + File dbFile = new File(subDir, j + SUF_FILE); + if (dbFile.exists()) { + try { + Files.delete(dbFile.toPath()); + } catch (IOException e) { + throw new RuntimeException("removeTable: " + + "cannon delete database file", e); + } + } + } + } + if (subDir.exists()) { + try { + Files.delete(subDir.toPath()); + } catch (DirectoryNotEmptyException e) { + throw new RuntimeException("removeTable: " + + "cannot remove table subdirectory", e); + } catch (IOException e) { + throw new RuntimeException("removeTable: " + + "cannot delete database subdirectory", e); + } + } + } + try { + Files.delete(table.toPath()); + } catch (DirectoryNotEmptyException e) { + throw new RuntimeException("removeTable: cannot remove main table directory", e); + } catch (IOException e) { + throw new RuntimeException("removeTable: cannot delete main database directory", e); + } + tables.remove(name); + } else { + throw new IllegalStateException("removeTable: " + name + "doesn't exist"); + } + } + + public Table getUsing() { + return tables.get(using); + } + + public void changeUsingTable(String table) { + using = table; + } + + + public Set> entrySet() { + return tables.entrySet(); + } + + + +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTableProviderFactory.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTableProviderFactory.java new file mode 100644 index 000000000..1ae2d83b0 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/MyTableProviderFactory.java @@ -0,0 +1,15 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +import ru.fizteh.fivt.storage.strings.TableProviderFactory; + +public class MyTableProviderFactory implements TableProviderFactory { + + @Override + public MyTableProvider create(String dir) { + if (dir == null) { + throw new IllegalArgumentException("create: " + dir + + " isn't a directory. "); + } + return new MyTableProvider(dir); + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/PackageParse.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/PackageParse.java new file mode 100644 index 000000000..741f49097 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/PackageParse.java @@ -0,0 +1,45 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.commands.Commands; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +public class PackageParse { + public static void parse(MyTableProvider directory, String[] arg) { + try { + ArrayList current = new ArrayList(); + for (int i = 0; i < arg.length; ++i) { + current.clear(); + while (i < arg.length) { + if (!(arg[i].contains(";"))) { + current.add(arg[i]); + i++; + } else { + current.add(arg[i].substring(0, arg[i].indexOf(";"))); + break; + } + } + if (current.size() == 0) { + return; + } + String[] com = new String[current.size()]; + com = current.toArray(com); + try { + Commands command = Commands.fromString(com); + command.execute(directory); + } catch (NoSuchElementException e) { + System.err.println(e.getMessage()); + } + } + directory.getUsing().commit(); + } catch (IllegalMonitorStateException e) { + System.out.println("Goodbye"); + System.exit(0); + } catch (IllegalArgumentException e) { + HandlerException.handler("Wrong arguments", e); + } catch (Exception e) { + HandlerException.handler( e); + } + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/ParserCommands.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/ParserCommands.java new file mode 100644 index 000000000..e98ff57ad --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/ParserCommands.java @@ -0,0 +1,225 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +import java.util.ArrayList; +import java.util.Map; + +public class ParserCommands { + + private static int numberChanges = 0; + + + public static void commandsExecution(String[] command, MyTableProvider directory) + throws IllegalMonitorStateException { + if (command.length == 0) { + return; + } + try { + Commands request = Commands.getCommand(command[0]); + switch (request) { + case CREATECOMMAND: + try { + try { + if (command[2] != null) { + System.err.println("create: need only one argument"); + } + } catch (ArrayIndexOutOfBoundsException e) { + + if (directory.createTable(command[1]) == null) { + System.out.println(command[1] + " exists"); + } else { + System.out.println("created"); + } + } + } catch (UnsupportedOperationException e) { + HandlerException.handler(e); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("create: need only one argument"); + } + break; + case PUTCOMMAND: + try { + try { + if (command[3] != null) { + System.err.println("create: need two arguments"); + } + } catch (ArrayIndexOutOfBoundsException e) { + if (directory.getUsing() == null) { + System.out.println("no table"); + } else { + String oldValue = directory.getUsing().put(command[1], command[2]); + if (oldValue != null) { + System.out.println("overwrite"); + System.out.println(oldValue); + } else { + System.out.println("new"); + } + numberChanges++; + } + } + + } catch (UnsupportedOperationException e) { + HandlerException.handler(e); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("put: need two arguments"); + } catch (NullPointerException e) { + HandlerException.handler(e); + } catch (Exception e) { + HandlerException.handler("ParserCommands.commandsExecution.put: ", e); + } + break; + case GETCOMMAND: + try { + try { + if (command[2] != null) { + System.err.println("create: need only one argument"); + } + } catch (ArrayIndexOutOfBoundsException e) { + if (directory.getUsing() == null) { + System.out.println("no table"); + } else { + String value = directory.getUsing().get(command[1]); + if (value != null) { + System.out.println("found"); + System.out.println(value); + } else { + System.out.println("not found"); + } + } + } + } catch (IllegalArgumentException e) { + System.out.println("not found"); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("get: need only one argument"); + } + break; + case REMOVECOMMAND: + try { + try { + if (command[2] != null) { + System.err.println("create: need only one argument"); + } + } catch (ArrayIndexOutOfBoundsException e) { + if (directory.getUsing() == null) { + System.out.println("no table"); + } else { + String oldValue = directory.getUsing().remove(command[1]); + if (oldValue != null) { + System.out.println("removed"); + numberChanges++; + } else { + System.out.println("not found"); + } + } + } + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("remove: need only one argument"); + } + break; + case DROPCOMMAND: + try { + try { + if (command[2] != null) { + System.err.println("create: need only one argument"); + } + } catch (ArrayIndexOutOfBoundsException e) { + if (directory.getTable(command[1]) == directory.getUsing()) { + numberChanges = 0; + } + directory.removeTable(command[1]); + System.out.println("dropped"); + } + } catch (IllegalStateException e) { + System.out.println(command[1] + " not exist"); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("drop: need only one argument"); + } + break; + case COMMITCOMMAND: + directory.getUsing().commit(); + System.out.println(numberChanges); + numberChanges = 0; + break; + case ROLLBACKCOMMAND: + System.out.println(directory.getUsing().rollback()); + numberChanges = 0; + break; + case USECOMMAND: + try { + try { + if (command[2] != null) { + System.err.println("create: need only one argument"); + } + } catch (ArrayIndexOutOfBoundsException e) { + if (numberChanges == 0) { + if (!directory.containsKey(command[1])) { + System.err.println("use: " + command[1] + " not exists"); + } else { + directory.changeUsingTable(command[1]); + System.out.println("using " + command[1]); + } + } else { + System.err.println(numberChanges + " unsaved changes"); + } + } + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("use: need argument"); + } + break; + case SHOWCOMMAND: + try { + if (command[1].equals("tables")) { + for (Map.Entry entry: directory.entrySet()) { + String name = entry.getKey(); + + int size = entry.getValue().size(); + System.out.println(name + " " + size); + } + + } else { + throw new IllegalArgumentException(); + } + + } catch (IllegalArgumentException e) { + System.err.println(command[0] + " - unknown command"); + } + break; + case LISTCOMMAND: + if (directory.getUsing() == null) { + System.out.println("no table"); + } else { + System.out.println(directory.getUsing().list()); + } + break; + case SIZECOMMAND: + if (directory.getUsing() == null) { + System.out.println("no table"); + } else { + System.out.println(directory.getUsing().size()); + } + break; + case EXITCOMMAND: + if (numberChanges == 0) { + throw new IllegalMonitorStateException("Exit"); + } else { + System.err.println(numberChanges + " unsaved changes"); + } + break; + default: + System.err.println(command[0] + " - unknown command"); + } + } catch (IllegalArgumentException e) { + System.err.println(e.getMessage()); + } + } + + + + public static void commandsExecution(ArrayList commands, MyTableProvider directory) { + if (commands.size() == 0) { + return; + } + String[] com = new String[commands.size()]; + com = commands.toArray(com); + commandsExecution(com, directory); + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/Runner.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/Runner.java new file mode 100644 index 000000000..172ef1a9d --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/Runner.java @@ -0,0 +1,26 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit; + +public class Runner { + public static void main(String[] args) { + + try { + String path = System.getProperty("fizteh.db.dir"); + if (path == null) { + throw new IllegalArgumentException("Directory doesn't exist"); + } + MyTableProviderFactory factory = new MyTableProviderFactory(); + MyTableProvider base = factory.create(path); + + + if (args.length == 0) { + InteractiveParse.parse(base); + } else { + PackageParse.parse(base, args); + } + } catch (IllegalArgumentException e) { + HandlerException.handler(e); + } + } + +} + diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/Commands.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/Commands.java new file mode 100644 index 000000000..1b0b6527a --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/Commands.java @@ -0,0 +1,52 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +import java.util.HashMap; +import java.util.NoSuchElementException; + +public abstract class Commands { + private static final HashMap COMMANDS; + + static { + COMMANDS = new HashMap<>(); + COMMANDS.put("create", new CreateCommand()); + COMMANDS.put("drop", new DropCommand()); + COMMANDS.put("use", new UseCommand()); + COMMANDS.put("show_tables", new ShowTablesCommand()); + COMMANDS.put("put", new PutCommand()); + COMMANDS.put("get", new GetCommand()); + COMMANDS.put("remove", new RemoveCommand()); + COMMANDS.put("list", new ListCommand()); + COMMANDS.put("exit", new ExitCommand()); + COMMANDS.put("commit", new CommitCommand()); + COMMANDS.put("rollback", new RollbackCommand()); + COMMANDS.put("size", new SizeCommand()); + } + + public static Commands fromString(String[] s) throws Exception { + if (s[0].equals("")) { + throw new NoSuchElementException(""); + } + if (s[0].equals("show")) { + s[0] += "_" + s[1]; + } + + if (COMMANDS.containsKey(s[0])) { + Commands command = COMMANDS.get(s[0]); + if (s.length - 1 != command.numberOfArguments()) { + throw new NoSuchElementException("Unexpected number of arguments: " + + command.numberOfArguments() + " required"); + } + command.putArguments(s); + return command; + } else { + throw new NoSuchElementException(s[0] + " is unknown command"); + } + } + + public abstract void execute(MyTableProvider provider); + protected void putArguments(String[] args) { + } + protected abstract int numberOfArguments(); +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/CommitCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/CommitCommand.java new file mode 100644 index 000000000..0e5ced63f --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/CommitCommand.java @@ -0,0 +1,19 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class CommitCommand extends Commands { + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null) { + System.out.println("no table"); + } else { + System.out.println(base.getUsing().commit()); + } + } + + @Override + protected int numberOfArguments() { + return 0; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/CreateCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/CreateCommand.java new file mode 100644 index 000000000..f70cf1c08 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/CreateCommand.java @@ -0,0 +1,24 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class CreateCommand extends Commands { + private String tableName; + + @Override + public void execute(MyTableProvider base) { + if (base.createTable(tableName) == null) { + System.out.println(tableName + " exists"); + } else { + System.out.println("created"); + } + } + + protected final void putArguments(String[] args) { + tableName = args[1]; + } + + protected final int numberOfArguments() { + return 1; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/DropCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/DropCommand.java new file mode 100644 index 000000000..670145aa8 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/DropCommand.java @@ -0,0 +1,28 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class DropCommand extends Commands { + private String tableName; + + @Override + public void execute(MyTableProvider base) { + try { + if (base.getTable(tableName) == base.getUsing()) { + base.changeUsingTable(null); + } + base.removeTable(tableName); + System.out.println("dropped"); + } catch (IllegalStateException e) { + System.out.println(tableName + " not exists"); + } + } + + protected final void putArguments(String[] args) { + tableName = args[1]; + } + + protected final int numberOfArguments() { + return 1; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ExitCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ExitCommand.java new file mode 100644 index 000000000..b4d129013 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ExitCommand.java @@ -0,0 +1,20 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTable; +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class ExitCommand extends Commands { + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null || ((MyTable) base.getUsing()).unsavedChanges() == 0) { + throw new IllegalMonitorStateException("Exit"); + } else { + System.err.println(((MyTable) base.getUsing()).unsavedChanges() + " unsaved changes"); + } + } + + @Override + protected int numberOfArguments() { + return 0; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/GetCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/GetCommand.java new file mode 100644 index 000000000..74b36ddfa --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/GetCommand.java @@ -0,0 +1,32 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class GetCommand extends Commands { + + private String key; + + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null) { + System.out.println("no table"); + } else { + String result = base.getUsing().get(key); + if (result == null) { + System.out.println("not found"); + } else { + System.out.println("found"); + System.out.println(result); + } + } + } + + protected final void putArguments(String[] args) { + key = args[1]; + } + + @Override + protected int numberOfArguments() { + return 1; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ListCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ListCommand.java new file mode 100644 index 000000000..18f57b68d --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ListCommand.java @@ -0,0 +1,19 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class ListCommand extends Commands { + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null) { + System.out.println("no table"); + } else { + System.out.println(String.join(", ", base.getUsing().list())); + } + } + + @Override + protected int numberOfArguments() { + return 0; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/PutCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/PutCommand.java new file mode 100644 index 000000000..4b2a9a26e --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/PutCommand.java @@ -0,0 +1,36 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class PutCommand extends Commands { + + private String key; + private String value; + + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null) { + System.out.println("no table"); + } else { + String result = base.getUsing().put(key, value); + if (result == null) { + System.out.println("new"); + } else { + System.out.println("overwrite"); + System.out.println(result); + } + } + } + + @Override + protected int numberOfArguments() { + return 2; + } + + @Override + protected void putArguments(String[] args) { + key = args[1]; + value = args[2]; + } +} + diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/RemoveCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/RemoveCommand.java new file mode 100644 index 000000000..d7deadec0 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/RemoveCommand.java @@ -0,0 +1,32 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class RemoveCommand extends Commands { + + private String key; + + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null) { + System.out.println("no table"); + } else { + String result = base.getUsing().remove(key); + if (result != null) { + System.out.println("removed"); + } else { + System.out.println("not found"); + } + } + } + + protected final void putArguments(String[] args) { + key = args[1]; + } + + @Override + protected int numberOfArguments() { + return 1; + } +} + diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/RollbackCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/RollbackCommand.java new file mode 100644 index 000000000..510764e48 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/RollbackCommand.java @@ -0,0 +1,20 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class RollbackCommand extends Commands { + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null) { + System.out.println("no table"); + } else { + System.out.println(base.getUsing().rollback()); + } + } + + @Override + protected int numberOfArguments() { + return 0; + } +} + diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ShowTablesCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ShowTablesCommand.java new file mode 100644 index 000000000..a5db48886 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/ShowTablesCommand.java @@ -0,0 +1,24 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTable; +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +import java.util.Map; + +public class ShowTablesCommand extends Commands { + @Override + public void execute(MyTableProvider base) { + for (Map.Entry entry: base.entrySet()) { + String name = entry.getKey(); + + int size = entry.getValue().size(); + System.out.println(name + " " + size); + } + } + + @Override + protected int numberOfArguments() { + return 1; + } +} + diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/SizeCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/SizeCommand.java new file mode 100644 index 000000000..7697b4c11 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/SizeCommand.java @@ -0,0 +1,19 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class SizeCommand extends Commands { + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() == null) { + System.out.println("no table"); + } else { + System.out.println(base.getUsing().size()); + } + } + + @Override + protected int numberOfArguments() { + return 0; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/UseCommand.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/UseCommand.java new file mode 100644 index 000000000..9c70b9fcd --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/commands/UseCommand.java @@ -0,0 +1,33 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.commands; + +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTable; +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProvider; + +public class UseCommand extends Commands { + + String tableName; + + @Override + public void execute(MyTableProvider base) { + if (base.getUsing() != null && ((MyTable) base.getUsing()).unsavedChanges() != 0) { + System.out.println(((MyTable) base.getUsing()).unsavedChanges() + " unsaved changes"); + } else { + if (base.getTable(tableName) == null) { + System.out.println(tableName + " not exists"); + } else { + base.changeUsingTable(tableName); + System.out.println("using " + tableName); + } + } + } + + @Override + protected int numberOfArguments() { + return 1; + } + + @Override + protected void putArguments(String[] args) { + tableName = args[1]; + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableProviderFactoryTest.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableProviderFactoryTest.java new file mode 100644 index 000000000..5a98b4ca6 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableProviderFactoryTest.java @@ -0,0 +1,40 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.test; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.strings.TableProviderFactory; +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProviderFactory; + +import java.io.IOException; + +import static junit.framework.Assert.assertNotNull; + +public class MyTableProviderFactoryTest { + + private TableProviderFactory factory; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @Before + public void before() { + factory = new MyTableProviderFactory(); + } + + @Test + public void create() throws IOException { + assertNotNull(factory.create(folder.newFolder("test").getCanonicalPath())); + } + + @Test(expected = IllegalArgumentException.class) + public void createWithNullArgument() { + factory.create(null); + } + + @Test(expected = IllegalArgumentException.class) + public void createWithIncorrectArgument() throws IOException { + factory.create(""); + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableProviderTest.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableProviderTest.java new file mode 100644 index 000000000..272061197 --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableProviderTest.java @@ -0,0 +1,69 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.test; + + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.strings.TableProvider; +import ru.fizteh.fivt.storage.strings.TableProviderFactory; +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProviderFactory; + +import java.io.IOException; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class MyTableProviderTest { + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + public TableProvider provider; + + @Before + public void initProvider() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + provider = factory.create(folder.newFolder("test").getAbsolutePath()); + } + + @Test (expected = IllegalArgumentException.class) + public void getNullTable() { + provider.getTable(null); + } + + @Test (expected = IllegalArgumentException.class) + public void createNullTable() { + provider.createTable(null); + } + + @Test (expected = IllegalArgumentException.class) + public void removeNullTable() { + provider.removeTable(null); + } + + @Test + public void createAndGetTable() { + provider.createTable("newTable"); + assertNull(provider.getTable("notExistingTable")); + assertNotNull(provider.getTable("newTable")); + } + + @Test (expected = IllegalStateException.class) + public void removeNotExistingTable() { + provider.removeTable("notExistingTable"); + } + + @Test + public void createAndRemoveTable() { + assertNotNull(provider.createTable("newTable")); + assertNotNull(provider.getTable("newTable")); + provider.removeTable("newTable"); + assertNull(provider.getTable("newTable")); + } + + @Test + public void doubleTableCreation() { + assertNotNull(provider.createTable("newTable")); + assertNull(provider.createTable("newTable")); + } +} diff --git a/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableTest.java b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableTest.java new file mode 100644 index 000000000..b1a81255d --- /dev/null +++ b/src/ru/fizteh/fivt/students/elina_denisova/j_unit/test/MyTableTest.java @@ -0,0 +1,152 @@ +package ru.fizteh.fivt.students.elina_denisova.j_unit.test; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.strings.Table; +import ru.fizteh.fivt.storage.strings.TableProvider; +import ru.fizteh.fivt.storage.strings.TableProviderFactory; +import ru.fizteh.fivt.students.elina_denisova.j_unit.MyTableProviderFactory; + +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedList; + +import static org.junit.Assert.*; + +public class MyTableTest { + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + public Table table; + public String dbDirPath; + + @Before + public void initTable() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + dbDirPath = folder.newFolder("test").getAbsolutePath(); + TableProvider provider = factory.create(dbDirPath); + table = provider.createTable("table"); + } + + @Test + public void testGetName() { + assertEquals("table", table.getName()); + } + + @Test (expected = IllegalArgumentException.class) + public void putNull() { + table.put(null, null); + } + + @Test (expected = IllegalArgumentException.class) + public void getNull() { + table.get(null); + } + + @Test (expected = IllegalArgumentException.class) + public void removeNull() { + table.remove(null); + } + + @Test + public void testPutAndGet() { + assertNull(table.put("1", "2")); + assertEquals("2", table.get("1")); + assertEquals("2", table.put("1", "3")); + assertEquals("3", table.get("1")); + assertNull(table.get("a")); + } + + @Test + public void testPutAndRemove() { + assertNull(table.put("1", "2")); + assertNull(table.remove("2")); + assertEquals("2", table.remove("1")); + assertNull(table.remove("1")); + assertNull(table.get("1")); + } + + @Test + public void testSize() { + assertEquals(0, table.size()); + table.put("1", "2"); + assertEquals(1, table.size()); + table.put("3", "4"); + assertEquals(2, table.size()); + table.put("3", "5"); + assertEquals(2, table.size()); + table.remove("1"); + assertEquals(1, table.size()); + table.remove("1"); + assertEquals(1, table.size()); + table.remove("3"); + assertEquals(0, table.size()); + } + + @Test + public void testList() { + assertEquals(0, table.list().size()); + table.put("1", "2"); + table.put("3", "4"); + table.put("3", "5"); + table.remove("1"); + table.put("6", "7"); + table.put("key", "value"); + assertEquals(3, table.list().size()); + assertTrue(table.list().containsAll(new LinkedList<>(Arrays.asList("3", "6", "key")))); + } + + @Test + public void testRollBack() { + assertEquals(0, table.rollback()); + table.put("1", "2"); + table.put("2", "3"); + table.put("3", "4"); + table.remove("1"); + table.put("1", "5"); + assertEquals(3, table.size()); + assertEquals(3, table.rollback()); + assertEquals(0, table.size()); + } + + @Test + public void testCommit() { + assertEquals(0, table.commit()); + table.put("1", "2"); + table.put("2", "3"); + table.put("3", "4"); + table.remove("3"); + assertEquals(2, table.commit()); + assertEquals(2, table.size()); + TableProviderFactory factory = new MyTableProviderFactory(); + TableProvider provider = factory.create(dbDirPath); + Table sameTable = provider.getTable("table"); + assertEquals(2, sameTable.size()); + } + + @Test + public void testCommitAndRollback() { + table.put("1", "2"); + table.put("2", "3"); + table.put("3", "4"); + assertEquals(3, table.commit()); + table.remove("1"); + table.remove("2"); + assertNull(table.get("1")); + assertNull(table.get("2")); + assertEquals(2, table.rollback()); + assertEquals("2", table.get("1")); + assertEquals("3", table.get("2")); + table.remove("1"); + assertEquals(1, table.commit()); + assertEquals(2, table.size()); + table.put("1", "2"); + assertEquals(3, table.size()); + assertEquals(1, table.rollback()); + assertEquals(2, table.size()); + assertEquals(null, table.get("1")); + } +}