From 81d2196127692284885cc9a17ead3b00a88dff0a Mon Sep 17 00:00:00 2001 From: taftafa Date: Fri, 12 Dec 2014 23:37:15 +0400 Subject: [PATCH 01/13] Commit JUnit --- .../fivt/students/kotsurba/junit/Context.java | 21 ++ .../students/kotsurba/junit/DataBase.java | 223 +++++++++++++ .../kotsurba/junit/DataBaseException.java | 7 + .../students/kotsurba/junit/DataBaseFile.java | 312 ++++++++++++++++++ .../kotsurba/junit/DataBaseTable.java | 90 +++++ .../junit/DataBaseWrongFileFormat.java | 7 + .../fivt/students/kotsurba/junit/DbMain.java | 102 ++++++ .../junit/MultiDataBaseException.java | 8 + .../junit/MyTableProviderFactory.java | 35 ++ .../kotsurba/junit/ShellCreateTable.java | 22 ++ .../kotsurba/junit/ShellDbCommit.java | 23 ++ .../students/kotsurba/junit/ShellDbGet.java | 29 ++ .../students/kotsurba/junit/ShellDbList.java | 35 ++ .../students/kotsurba/junit/ShellDbPut.java | 43 +++ .../kotsurba/junit/ShellDbRemove.java | 27 ++ .../kotsurba/junit/ShellDbRollback.java | 23 ++ .../students/kotsurba/junit/ShellDbShow.java | 28 ++ .../students/kotsurba/junit/ShellDbSize.java | 23 ++ .../kotsurba/junit/ShellDropTable.java | 28 ++ .../students/kotsurba/junit/ShellExit.java | 24 ++ .../kotsurba/junit/ShellExitException.java | 7 + .../kotsurba/junit/ShellUseTable.java | 29 ++ 22 files changed, 1146 insertions(+) create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/Context.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseWrongFileFormat.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/MultiDataBaseException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/MyTableProviderFactory.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbCommit.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbGet.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbPut.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRemove.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRollback.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbShow.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellDropTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/Context.java b/src/ru/fizteh/fivt/students/kotsurba/junit/Context.java new file mode 100644 index 000000000..357947064 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/Context.java @@ -0,0 +1,21 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.storage.strings.Table; +import ru.fizteh.fivt.storage.strings.TableProvider; + +public class Context { + public TableProvider provider; + public Table table; + + public Context(TableProvider newProvider) { + provider = newProvider; + table = null; + } + + public int getChanges() { + if (table != null) { + return ((DataBase) table).getNewKeys(); + } + return 0; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java new file mode 100644 index 000000000..b438e4ea6 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java @@ -0,0 +1,223 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.storage.strings.Table; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public final class DataBase implements Table { + + private String name; + private String dataBaseDirectory; + private DataBaseFile[] files; + + public final class DirFile { + private int nDir; + private int nFile; + + public DirFile(int key) { + key = Math.abs(key); + nDir = key % 16; + nFile = (key / 16) % 16; + } + + public DirFile(final int newDir, final int newFile) { + nDir = newDir; + nFile = newFile; + } + + private String getNDirectory() { + return Integer.toString(nDir) + ".dir"; + } + + private String getNFile() { + return Integer.toString(nFile) + ".dat"; + } + + public int getId() { + return nDir * 16 + nFile; + } + } + + public DataBase(final String dbDirectory) { + name = new File(dbDirectory).getName(); + dataBaseDirectory = dbDirectory; + isCorrect(); + files = new DataBaseFile[256]; + loadFiles(); + } + + private void checkNames(final String[] dirs, final String secondName) { + for (String dir : dirs) { + String[] name = dir.split("\\."); + if (name.length != 2 || !name[1].equals(secondName)) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file in path " + dir); + } + + int firstName; + try { + firstName = Integer.parseInt(name[0]); + } catch (NumberFormatException e) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dir); + } + + if ((firstName < 0) || firstName > 15) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dir); + } + } + } + + private void isCorrectDirectory(final String dirName) { + File file = new File(dirName); + if (file.isFile()) { + throw new MultiDataBaseException(dirName + " isn't a directory!"); + } + String[] dirs = file.list(); + checkNames(dirs, "dat"); + for (String dir : dirs) { + if (new File(dirName, dir).isDirectory()) { + throw new MultiDataBaseException(dirName + File.separator + dir + " isn't a file!"); + } + } + } + + private void isCorrect() { + File file = new File(dataBaseDirectory); + if (file.isFile()) { + throw new MultiDataBaseException(dataBaseDirectory + " isn't directory!"); + } + + String[] dirs = file.list(); + checkNames(dirs, "dir"); + for (String dir : dirs) { + isCorrectDirectory(dataBaseDirectory + File.separator + dir); + } + } + + private void tryDeleteDirectory(final String name) { + File file = new File(dataBaseDirectory + File.separator + name); + if (file.exists()) { + if (file.list().length == 0) { + if (!file.delete()) { + throw new DataBaseException("Cannot delete a directory!"); + } + } + } + } + + private String getFullName(final DirFile node) { + return dataBaseDirectory + File.separator + node.getNDirectory() + File.separator + node.getNFile(); + } + + public void loadFiles() { + for (int i = 0; i < 16; ++i) { + for (int j = 0; j < 16; ++j) { + DirFile node = new DirFile(i, j); + DataBaseFile file = new DataBaseFile(getFullName(node), node.nDir, node.nFile); + files[node.getId()] = file; + } + } + } + + private void checkKey(final String key) { + if ((key == null) || (key.trim().length() == 0)) { + throw new IllegalArgumentException("Wrong key!"); + } + } + + public void drop() { + for (byte i = 0; i < 16; ++i) { + for (byte j = 0; j < 16; ++j) { + File file = new File(getFullName(new DirFile(i, j))); + if (file.exists()) { + if (!file.delete()) { + throw new DataBaseException("Cannot delete a file!"); + } + } + } + tryDeleteDirectory(Integer.toString(i) + ".dir"); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public String put(final String keyStr, final String valueStr) { + checkKey(keyStr); + checkKey(valueStr); + DirFile node = new DirFile(keyStr.getBytes()[0]); + DataBaseFile file = files[node.getId()]; + return file.put(keyStr, valueStr); + } + + @Override + public String get(final String keyStr) { + checkKey(keyStr); + DirFile node = new DirFile(keyStr.getBytes()[0]); + DataBaseFile file = files[node.getId()]; + return file.get(keyStr); + } + + @Override + public String remove(final String keyStr) { + checkKey(keyStr); + DirFile node = new DirFile(keyStr.getBytes()[0]); + DataBaseFile file = files[node.getId()]; + return file.remove(keyStr); + } + + @Override + public int commit() { + int allNew = 0; + for (int i = 0; i < 256; ++i) { + allNew += files[i].getNewKeys(); + files[i].commit(); + } + return allNew; + } + + @Override + public int size() { + int allSize = 0; + for (int i = 0; i < 256; ++i) { + allSize += files[i].getSize(); + } + return allSize; + } + + @Override + public int rollback() { + int allCanceled = 0; + for (int i = 0; i < 256; ++i) { + allCanceled += files[i].getNewKeys(); + files[i].rollback(); + } + return allCanceled; + } + + public int getNewKeys() { + int allNewSize = 0; + for (int i = 0; i < 256; ++i) { + allNewSize += files[i].getNewKeys(); + } + return allNewSize; + } + + @Override + public List list() { + List result = new ArrayList(); + for (DataBaseFile dbf : files) { + if (dbf.getSize() != 0) { + List ans = dbf.getAllKeys(); + for (String x : ans) { + result.add(x); + } + } + } + return result; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java new file mode 100644 index 000000000..41e7c43f3 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +public class DataBaseException extends Error { + public DataBaseException(final String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java new file mode 100644 index 000000000..ea6fc6456 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java @@ -0,0 +1,312 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; +import java.io.File; +import java.io.FileNotFoundException; + +public class DataBaseFile { + + static final byte OLD_NODE = 1; + static final byte NEW_NODE = 2; + static final byte MODIFIED_NODE = 3; + static final byte DELETED_NODE = 4; + + + public final class Node { + private byte status; + private boolean old; + private byte[] key; + private byte[] value; + private byte[] oldValue; + + public int getZeroByte() { + return Math.abs(key[0]); + } + + public Node(final byte[] newKey, final byte[] newValue) { + status = NEW_NODE; + key = newKey; + value = newValue; + oldValue = null; + old = false; + } + + public Node(final RandomAccessFile inputFile) throws IOException { + status = OLD_NODE; + old = true; + try { + int keyLength = inputFile.readInt(); + int valueLength = inputFile.readInt(); + if ((keyLength <= 0) || (valueLength <= 0)) { + throw new DataBaseWrongFileFormat("Wrong file format! " + file.getName()); + } + try { + key = new byte[keyLength]; + value = new byte[valueLength]; + } catch (OutOfMemoryError e) { + throw new DataBaseWrongFileFormat("Some key or value are too large in " + file.getName()); + } + inputFile.read(key); + inputFile.read(value); + oldValue = value; + } catch (Exception e) { + throw new DataBaseWrongFileFormat("Wrong file format! " + file.getName()); + } + } + + public void setKey(final byte[] newKey) { + key = newKey; + } + + public void setValue(final byte[] newValue) { + status = MODIFIED_NODE; + if ((oldValue != null) && (Arrays.equals(oldValue, newValue))) { + status = OLD_NODE; + } + value = newValue; + } + + public void write(final RandomAccessFile outputFile) throws IOException { + if (status == DELETED_NODE) { + return; + } + outputFile.writeInt(key.length); + outputFile.writeInt(value.length); + outputFile.write(key); + outputFile.write(value); + } + + public byte getStatus() { + return status; + } + + public void setStatus(byte newStatus) { + status = newStatus; + } + + public void remove() { + value = null; + status = DELETED_NODE; + } + + } + + protected final String fileName; + protected File file; + private File dir; + protected List data; + private int fileNumber; + private int direcotryNumber; + + public DataBaseFile(final String newFileName, final int newDirectoryNumber, final int newFileNumber) { + fileName = newFileName; + file = new File(fileName); + data = new ArrayList(); + fileNumber = newFileNumber; + direcotryNumber = newDirectoryNumber; + String path = file.getParent(); + dir = new File(path); + load(); + check(); + } + + public boolean check() { + for (Node node : data) { + if (!((node.getZeroByte() % 16 == direcotryNumber) && ((node.getZeroByte() / 16) % 16 == fileNumber))) { + throw new DataBaseWrongFileFormat("Wrong file format key[0] = " + String.valueOf(node.getZeroByte()) + + " in file " + fileName); + } + } + return true; + } + + private void load() { + try { + if (!dir.exists() || !file.exists()) { + return; + } + RandomAccessFile inputFile = new RandomAccessFile(fileName, "rw"); + while (inputFile.getFilePointer() < inputFile.length() - 1) { + data.add(new Node(inputFile)); + } + inputFile.close(); + } catch (FileNotFoundException e) { + throw new DataBaseException("File not found!"); + } catch (IOException e) { + throw new DataBaseException("File load error!"); + } + } + + public void createPath() { + if (dir.exists()) { + return; + } + + if (!dir.mkdir()) { + throw new DataBaseException("Cannot create directory!"); + } + } + + public void deletePath() { + if (!dir.exists()) { + return; + } + + if (dir.list().length != 0) { + return; + } + + if (!dir.delete()) { + throw new DataBaseException("Cannot delete a directory!"); + } + } + + public void save() { + try { + if (getSize() == 0) { + if ((file.exists()) && (!file.delete())) { + throw new DataBaseException("Cannot delete a file!"); + } + deletePath(); + } else { + createPath(); + if (!file.exists()) { + if (!file.createNewFile()) { + throw new DataBaseException("Cannot create a file " + fileName); + } + } + RandomAccessFile outputFile = new RandomAccessFile(fileName, "rw"); + try { + for (Node node : data) { + node.write(outputFile); + } + outputFile.setLength(outputFile.getFilePointer()); + } finally { + outputFile.close(); + } + } + } catch (FileNotFoundException e) { + throw new DataBaseException("File save error!"); + } catch (IOException e) { + throw new DataBaseException("Write to file error!"); + } + } + + + private int search(final byte[] key) { + for (int i = 0; i < data.size(); ++i) { + if (Arrays.equals(data.get(i).key, key)) { + return i; + } + } + return -1; + } + + public String put(final String keyStr, final String valueStr) { + try { + byte[] key = keyStr.getBytes("UTF-8"); + byte[] value = valueStr.getBytes("UTF-8"); + + int index = search(key); + if (index == -1) { + data.add(new Node(key, value)); + return null; + } else { + int status = data.get(index).status; + String result = null; + if (status != DELETED_NODE) { + result = new String(data.get(index).value); + } + data.get(index).setValue(value); + return result; + } + } catch (UnsupportedEncodingException e) { + throw new DataBaseException(e.getMessage()); + } + } + + public String get(final String keyStr) { + try { + byte[] key = keyStr.getBytes("UTF-8"); + int index = search(key); + if (index != -1) { + if (data.get(index).status == DELETED_NODE) { + return null; + } + return new String(data.get(index).value); + } else { + return null; + } + } catch (UnsupportedEncodingException e) { + throw new DataBaseException(e.getMessage()); + } + } + + public String remove(final String keyStr) { + try { + byte[] key = keyStr.getBytes("UTF-8"); + int index = search(key); + if (index == -1) { + return null; + } else { + String result; + if (data.get(index).status == DELETED_NODE) { + result = null; + } else { + result = new String(data.get(index).value); + } + data.get(index).remove(); + return result; + } + } catch (UnsupportedEncodingException e) { + throw new DataBaseException(e.getMessage()); + } + } + + public int getNewKeys() { + int result = 0; + for (Node node : data) { + if ((node.getStatus() == NEW_NODE) || (node.getStatus() == MODIFIED_NODE) || + ((node.getStatus() == DELETED_NODE) && (node.old))) { + ++result; + } + } + return result; + } + + public int getSize() { + int result = 0; + for (Node node : data) { + if (node.getStatus() != DELETED_NODE) { + ++result; + } + } + return result; + } + + public List getAllKeys() { + List result = new ArrayList(); + for (Node node : data) { + if (node.getStatus() != DELETED_NODE) { + result.add(new String(node.key)); + } + } + return result; + } + + public void commit() { + save(); + data.clear(); + load(); + } + + public void rollback() { + data.clear(); + load(); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java new file mode 100644 index 000000000..f28669afa --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java @@ -0,0 +1,90 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.storage.strings.Table; +import ru.fizteh.fivt.storage.strings.TableProvider; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public final class DataBaseTable implements TableProvider { + private String tableDir; + private Map tableInUse; + + public DataBase getTableFromMap(final String name) { + if (!tableInUse.containsKey(name)) { + tableInUse.put(name, new DataBase(name)); + } + return tableInUse.get(name); + } + + public void deleteTableFromMap(final String name) { + if (tableInUse.containsKey(name)) { + tableInUse.remove(name); + } + } + + public DataBaseTable(String newTableDir) { + tableDir = newTableDir; + tableInUse = new HashMap(); + } + + private void checkName(final String name) { + if ((name == null) || name.trim().length() == 0) { + throw new IllegalArgumentException("Cannot create table! Wrong name!"); + } + + if (name.matches("[" + '"' + "'\\/:/*/?//|/.\\\\]+") || name.contains(File.separator) + || name.contains(".")) { + throw new RuntimeException("Wrong symbols in name!"); + } + } + + @Override + public Table createTable(final String tableName) { + checkName(tableName); + String fullPath = tableDir + File.separator + tableName; + + File file = new File(fullPath); + + if (file.exists()) { + return null; + } + + if (!file.mkdir()) { + throw new MultiDataBaseException("Cannot create table " + tableName); + } + + return getTableFromMap(fullPath); + } + + @Override + public void removeTable(final String tableName) { + checkName(tableName); + String fullPath = tableDir + File.separator + tableName; + + File file = new File(fullPath); + if (!file.exists()) { + throw new IllegalStateException("Table not exist already!"); + } + + DataBase base = getTableFromMap(fullPath); + base.drop(); + if (!file.delete()) { + throw new DataBaseException("Cannot delete a file " + tableName); + } + deleteTableFromMap(fullPath); + } + + @Override + public Table getTable(String tableName) { + checkName(tableName); + String fullPath = tableDir + File.separator + tableName; + + File file = new File(fullPath); + if ((!file.exists()) || (file.isFile())) { + return null; + } + return getTableFromMap(fullPath); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseWrongFileFormat.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseWrongFileFormat.java new file mode 100644 index 000000000..e18a87a90 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseWrongFileFormat.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +public class DataBaseWrongFileFormat extends Error { + public DataBaseWrongFileFormat(final String message) { + super(message); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java new file mode 100644 index 000000000..cc8e8174a --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java @@ -0,0 +1,102 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.storage.strings.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandParser; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.Shell; +import ru.fizteh.fivt.students.kotsurba.shell.ShellMain; + +import java.util.Scanner; + +public class DbMain { + private static Shell shell; + + private static void checkDbDir() { + if (!System.getProperties().containsKey("fizteh.db.dir")) { + System.err.println("Please set database directory!"); + System.err.println("-Dfizteh.db.dir="); + System.exit(1); + } + } + + private static void initShell() { + + shell = new Shell(); + + TableProviderFactory factory = new MyTableProviderFactory(); + Context context = new Context(factory.create(System.getProperty("fizteh.db.dir"))); + + shell.addCommand(new ShellDbPut(context)); + shell.addCommand(new ShellExit(context)); + shell.addCommand(new ShellDbGet(context)); + shell.addCommand(new ShellDbRemove(context)); + shell.addCommand(new ShellCreateTable(context)); + shell.addCommand(new ShellDropTable(context)); + shell.addCommand(new ShellUseTable(context)); + shell.addCommand(new ShellDbSize(context)); + shell.addCommand(new ShellDbCommit(context)); + shell.addCommand(new ShellDbRollback(context)); + shell.addCommand(new ShellDbList(context)); + shell.addCommand(new ShellDbShow(context)); + } + + private static void packetRun(final String[] args) { + try { + CommandParser parser = new CommandParser(args); + while (!parser.isEmpty()) { + shell.executeCommand(parser.getCommand()); + } + } catch (InvalidCommandException | MultiDataBaseException | DataBaseWrongFileFormat | RuntimeException e) { + System.err.println(e.getMessage()); + } + } + + private static void interactiveRun() { + Scanner scanner = new Scanner(System.in); + System.out.print("$ "); + while (true) { + try { + if (!scanner.hasNextLine()) { + throw new ShellExitException("Ctrl + D exit!"); + } + + String command = scanner.nextLine(); + + if (ShellMain.hasTerminalSymbol(command)) { + throw new ShellExitException("Ctrl + D exit or EOF!"); + } + + CommandParser parser = new CommandParser(command); + if (!parser.isEmpty()) { + shell.executeCommand(parser.getCommand()); + } + } catch (MultiDataBaseException | DataBaseWrongFileFormat | InvalidCommandException + | RuntimeException e) { + System.err.println(e.getMessage()); + } finally { + System.out.print("$ "); + } + } + } + + public static void main(final String[] args) { + try { + checkDbDir(); + initShell(); + + if (args.length > 0) { + packetRun(args); + } else { + interactiveRun(); + } + + } catch (DataBaseException e) { + System.err.println(e.getMessage()); + System.exit(1); + } catch (ShellExitException e) { + System.exit(0); + } finally { + System.exit(0); + } + } +} \ No newline at end of file diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/MultiDataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/junit/MultiDataBaseException.java new file mode 100644 index 000000000..3c10e9814 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/MultiDataBaseException.java @@ -0,0 +1,8 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +public class MultiDataBaseException extends Error { + public MultiDataBaseException(final String message) { + super(message); + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/MyTableProviderFactory.java b/src/ru/fizteh/fivt/students/kotsurba/junit/MyTableProviderFactory.java new file mode 100644 index 000000000..74a1383db --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/MyTableProviderFactory.java @@ -0,0 +1,35 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.storage.strings.TableProvider; +import ru.fizteh.fivt.storage.strings.TableProviderFactory; + +import java.io.File; +import java.io.IOException; + +public class MyTableProviderFactory implements TableProviderFactory { + + @Override + public TableProvider create(String dir) { + if (dir == null) { + throw new IllegalArgumentException("Dir cannot be null"); + } + + File tableDirFile = new File(dir); + + if (!tableDirFile.exists()) { + if (!tableDirFile.mkdirs()) { + try { + throw new IllegalArgumentException("Cannot create directory! " + tableDirFile.getCanonicalPath()); + } catch (IOException e) { + throw new RuntimeException("Mkdirs failed", e); + } + } + } + + if (!tableDirFile.isDirectory()) { + throw new IllegalArgumentException("Wrong dir " + dir); + } + + return new DataBaseTable(dir); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java new file mode 100644 index 000000000..452f696ce --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java @@ -0,0 +1,22 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellCreateTable extends SimpleShellCommand { + private Context context; + + public ShellCreateTable(Context newContext) { + context = newContext; + setName("create"); + setNumberOfArgs(2); + setHint("usage: create "); + } + + public void run() { + if (context.provider.createTable(getArg(1)) != null) { + System.out.println("created"); + } else { + System.out.println(getArg(1) + " exists"); + } + } +} \ No newline at end of file diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbCommit.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbCommit.java new file mode 100644 index 000000000..da5015807 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbCommit.java @@ -0,0 +1,23 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDbCommit extends SimpleShellCommand { + private Context context; + + public ShellDbCommit(final Context newContext) { + context = newContext; + setName("commit"); + setNumberOfArgs(1); + setHint("usage: commit"); + } + + @Override + public void run() { + if (context.table != null) { + System.out.println(context.table.commit()); + } else { + System.out.println("no table"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbGet.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbGet.java new file mode 100644 index 000000000..a8591d7b6 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbGet.java @@ -0,0 +1,29 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDbGet extends SimpleShellCommand { + private Context context; + + public ShellDbGet(final Context newContext) { + context = newContext; + setName("get"); + setNumberOfArgs(2); + setHint("usage: get "); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + String str = context.table.get(getArg(1)); + if (str == null) { + System.out.println("not found"); + } else { + System.out.println("found"); + System.out.println(str); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java new file mode 100644 index 000000000..92d7698e4 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java @@ -0,0 +1,35 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.util.List; + +public final class ShellDbList extends SimpleShellCommand { + private Context context; + + public ShellDbList(final Context newContext) { + context = newContext; + setName("list"); + setNumberOfArgs(1); + setHint("usage: list"); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + List str = context.table.list(); + StringBuilder keys = new StringBuilder(); + for (String string : str) { + keys.append(string).append(", "); + } + if (keys.length() > 1) { + keys.deleteCharAt(keys.length() - 1); + keys.deleteCharAt(keys.length() - 1); + } + System.out.println(keys); + } + +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbPut.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbPut.java new file mode 100644 index 000000000..64b4d29c8 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbPut.java @@ -0,0 +1,43 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandString; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public final class ShellDbPut extends SimpleShellCommand { + private Context context; + + public ShellDbPut(final Context newContext) { + context = newContext; + setName("put"); + setNumberOfArgs(3); + setHint("usage: put "); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + String str = context.table.put(getArg(1), getSpacedArg(2)); + if (str == null) { + System.out.println("new"); + } else { + System.out.println("overwrite"); + System.out.println(str); + } + } + + @Override + public boolean isMyCommand(final CommandString command) { + if (name.equals(command.getArg(0))) { + if (command.length() < numberOfArgs) { + throw new InvalidCommandException(name + " " + hint); + } + args = command; + return true; + } + return false; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRemove.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRemove.java new file mode 100644 index 000000000..25acf4478 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRemove.java @@ -0,0 +1,27 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public final class ShellDbRemove extends SimpleShellCommand { + private Context context; + + public ShellDbRemove(Context newContext) { + context = newContext; + setName("remove"); + setNumberOfArgs(2); + setHint("usage: remove "); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + if (context.table.remove(getArg(1)) == null) { + System.out.println("not found"); + } else { + System.out.println("removed"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRollback.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRollback.java new file mode 100644 index 000000000..577868c2c --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbRollback.java @@ -0,0 +1,23 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDbRollback extends SimpleShellCommand { + private Context context; + + public ShellDbRollback(final Context newContext) { + context = newContext; + setName("rollback"); + setNumberOfArgs(1); + setHint("usage: rollback"); + } + + @Override + public void run() { + if (context.table != null) { + System.out.println(context.table.rollback()); + } else { + System.out.println("no table"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbShow.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbShow.java new file mode 100644 index 000000000..d5ebb2130 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbShow.java @@ -0,0 +1,28 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.io.File; + +public class ShellDbShow extends SimpleShellCommand { + + public ShellDbShow(Context newContext) { + setName("show"); + setNumberOfArgs(2); + setHint("usage: show tables"); + } + + public void run() { + if (getArg(1).equals("tables")) { + DataBase mdb; + String tableDir = System.getProperty("fizteh.db.dir"); + + for (String str : new File(tableDir).list()) { + mdb = new DataBase(tableDir + File.separator + str); + System.out.println(str + " " + mdb.size()); + } + } else { + System.out.println("Invalid command!"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java new file mode 100644 index 000000000..433e14ff5 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java @@ -0,0 +1,23 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDbSize extends SimpleShellCommand { + private Context context; + + public ShellDbSize(final Context newContext) { + context = newContext; + setName("size"); + setNumberOfArgs(1); + setHint("usage: size"); + } + + @Override + public void run() { + if (context.table != null) { + System.out.println(context.table.size()); + } else { + System.out.println("no table"); + } + } +} \ No newline at end of file diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDropTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDropTable.java new file mode 100644 index 000000000..741f707d4 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDropTable.java @@ -0,0 +1,28 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDropTable extends SimpleShellCommand { + private Context context; + + public ShellDropTable(Context newContext) { + context = newContext; + setName("drop"); + setNumberOfArgs(2); + setHint("usage: drop
"); + } + + public void run() { + try { + if ((context.table != null) && (context.table.getName().equals(getArg(1)))) { + context.table = null; + } + + context.provider.removeTable(getArg(1)); + System.out.println("dropped"); + } catch (IllegalStateException e) { + System.out.println(getArg(1) + " not exists"); + } + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java new file mode 100644 index 000000000..40871dfcb --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java @@ -0,0 +1,24 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public final class ShellExit extends SimpleShellCommand { + private Context context; + + public ShellExit(final Context newContext) { + context = newContext; + setName("exit"); + setNumberOfArgs(1); + setHint("usage: exit"); + } + + @Override + public void run() { + if (context.getChanges() == 0) { + throw new ShellExitException("Exit command"); + } else { + System.out.println(context.getChanges() + " unsaved changes"); + } + } + +} \ No newline at end of file diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java new file mode 100644 index 000000000..29d9c1367 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +public class ShellExitException extends Error { + public ShellExitException(final String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java new file mode 100644 index 000000000..af651e8d2 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java @@ -0,0 +1,29 @@ +package ru.fizteh.fivt.students.kotsurba.junit; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellUseTable extends SimpleShellCommand { + private Context context; + + public ShellUseTable(Context newContext) { + context = newContext; + setName("use"); + setNumberOfArgs(2); + setHint("usage: use
"); + } + + public void run() { + + if ((context.table != null) && (context.getChanges() != 0)) { + System.out.println(context.getChanges() + " unsaved changes"); + return; + } + + context.table = context.provider.getTable(getArg(1)); + if (context.table != null) { + System.out.println("using " + getArg(1)); + } else { + System.out.println(getArg(1) + " not exists"); + } + } +} \ No newline at end of file From 6ed5a30ae8f387afdb3a0e67d642213ab8cb30de Mon Sep 17 00:00:00 2001 From: taftafa Date: Sat, 13 Dec 2014 01:10:22 +0400 Subject: [PATCH 02/13] Checkstyle... --- .../fizteh/fivt/students/kotsurba/junit/DataBaseException.java | 2 +- src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java | 2 +- .../fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java | 2 +- src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java | 1 - src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java | 2 +- src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java | 3 +-- .../fivt/students/kotsurba/junit/ShellExitException.java | 2 +- src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java | 2 +- 8 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java index 41e7c43f3..60e61274c 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseException.java @@ -4,4 +4,4 @@ public class DataBaseException extends Error { public DataBaseException(final String message) { super(message); } -} \ No newline at end of file +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java index cc8e8174a..acb9cff04 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DbMain.java @@ -99,4 +99,4 @@ public static void main(final String[] args) { System.exit(0); } } -} \ No newline at end of file +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java index 452f696ce..fafb96987 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellCreateTable.java @@ -19,4 +19,4 @@ public void run() { System.out.println(getArg(1) + " exists"); } } -} \ No newline at end of file +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java index 92d7698e4..92f88baa5 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbList.java @@ -31,5 +31,4 @@ public void run() { } System.out.println(keys); } - } diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java index 433e14ff5..c138e1795 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellDbSize.java @@ -20,4 +20,4 @@ public void run() { System.out.println("no table"); } } -} \ No newline at end of file +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java index 40871dfcb..1d2a967be 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExit.java @@ -20,5 +20,4 @@ public void run() { System.out.println(context.getChanges() + " unsaved changes"); } } - -} \ No newline at end of file +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java index 29d9c1367..51ce75266 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellExitException.java @@ -4,4 +4,4 @@ public class ShellExitException extends Error { public ShellExitException(final String message) { super(message); } -} \ No newline at end of file +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java index af651e8d2..904db1972 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/ShellUseTable.java @@ -26,4 +26,4 @@ public void run() { System.out.println(getArg(1) + " not exists"); } } -} \ No newline at end of file +} From 6603b7b561c3a250bee50094662ca51bc8ebd7f1 Mon Sep 17 00:00:00 2001 From: taftafa Date: Sat, 13 Dec 2014 01:13:47 +0400 Subject: [PATCH 03/13] Commit tests for JUnit. --- .../tests/MyTableProviderFactoryTest.java | 25 +++ .../junit/tests/MyTableProviderTest.java | 105 ++++++++++ .../kotsurba/junit/tests/MyTableTest.java | 185 ++++++++++++++++++ 3 files changed, 315 insertions(+) create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java new file mode 100644 index 000000000..08ef49673 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java @@ -0,0 +1,25 @@ +package ru.fizteh.fivt.students.kotsurba.junit.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.strings.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.junit.MyTableProviderFactory; + +import java.io.IOException; + +public class MyTableProviderFactoryTest { + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @Test(expected = IllegalArgumentException.class) + public void testCreateNull() { + TableProviderFactory factory = new MyTableProviderFactory(); + factory.create(null); + } + + @Test + public void testCreateNotNull() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + Assert.assertNotNull(factory.create(folder.newFolder("folder").getCanonicalPath())); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java new file mode 100644 index 000000000..89621479f --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java @@ -0,0 +1,105 @@ +package ru.fizteh.fivt.students.kotsurba.junit.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.strings.TableProvider; +import ru.fizteh.fivt.storage.strings.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.junit.MyTableProviderFactory; + +import java.io.File; +import java.io.IOException; + +public class MyTableProviderTest { + static TableProviderFactory factory; + static TableProvider provider; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void before() throws IOException { + provider = factory.create(folder.newFolder().getCanonicalPath()); + Assert.assertNotNull(provider); + } + + @Test + public void testCreateRemoveTable() { + Assert.assertNotNull(provider.createTable("test_create_table")); + Assert.assertNull(provider.createTable("test_create_table")); + provider.removeTable("test_create_table"); + } + + @Test(expected = IllegalStateException.class) + public void testRemoveNonExistingTable() { + provider.removeTable("non_existing_table"); + } + + @Test(expected = RuntimeException.class) + public void testGetTableWithWrongName() { + provider.getTable(".." + File.separator + "database"); + } + + @Test(expected = RuntimeException.class) + public void testCreateTableWithWrongName() { + provider.createTable(".." + File.separator + "database"); + } + + @Test(expected = RuntimeException.class) + public void testUseTableWithWrongName() { + provider.removeTable(".." + File.separator + "database"); + } + + @Test + public void testGetTable() { + provider.createTable("test_get_table"); + Assert.assertNotNull(provider.getTable("test_get_table")); + provider.removeTable("test_get_table"); + } + + @Test + public void testGetNonExistingTable() { + Assert.assertNull(provider.getTable("non_existing_table")); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetTableWithNull() { + provider.getTable(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateTableWithNull() { + provider.createTable(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testRemoveTableWithNull() { + provider.removeTable(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateTableWithEmptyName() { + provider.createTable(""); + } + + @Test(expected = IllegalArgumentException.class) + public void testRemoveTableWithEmptyName() { + provider.removeTable(""); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetTableWithEmptyName() { + provider.getTable(""); + } + + @Test + public void testSameInstanceGetCreate() { + Assert.assertEquals(provider.createTable("instance"), provider.getTable("instance")); + Assert.assertEquals(provider.getTable("instance"), provider.getTable("instance")); + provider.removeTable("instance"); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java new file mode 100644 index 000000000..0a54b106a --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java @@ -0,0 +1,185 @@ +package ru.fizteh.fivt.students.kotsurba.junit.tests; + +import org.junit.*; +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.kotsurba.junit.MyTableProviderFactory; + +import java.io.IOException; +import java.util.*; + +public class MyTableTest { + static Table table; + static TableProviderFactory factory; + static TableProvider provider; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void beforeTest() throws IOException { + provider = factory.create(folder.newFolder("folder").getCanonicalPath()); + table = provider.createTable("new"); + } + + @After + public void afterTest() { + provider.removeTable("new"); + } + + + @Test + public void testGetName() { + Assert.assertEquals(table.getName(), "new"); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetNull() { + table.get(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutNull() { + table.put(null, "test"); + } + + @Test(expected = IllegalArgumentException.class) + public void testRemoveNull() { + table.remove(null); + } + + @Test + public void testPutGetRemoveEnglish() { + Assert.assertNull(table.put("key", "value")); + Assert.assertEquals(table.get("key"), "value"); + Assert.assertNull(table.get("value")); + Assert.assertEquals(table.put("key", "value_new"), "value"); + Assert.assertEquals(table.remove("key"), "value_new"); + } + + @Test + public void testPutGetRemoveRussian() { + Assert.assertNull(table.put("МАМА", "ПАПА")); + Assert.assertEquals(table.get("МАМА"), "ПАПА"); + Assert.assertNull(table.get("ПАПА")); + Assert.assertEquals(table.put("МАМА", "БРАТ"), "ПАПА"); + Assert.assertEquals(table.remove("МАМА"), "БРАТ"); + } + + @Test + public void testSizeCommit() { + Assert.assertEquals(table.size(), 0); + int count = (Math.abs(new Random().nextInt()) % 255) + 100; + for (int i = 0; i < count; ++i) { + Assert.assertNull(table.put(Integer.toString(i), "size test")); + } + Assert.assertEquals(table.size(), count); + Assert.assertEquals(table.commit(), count); + for (int i = 0; i < count; ++i) { + Assert.assertEquals(table.remove(Integer.toString(i)), "size test"); + } + Assert.assertEquals(table.size(), 0); + Assert.assertEquals(table.commit(), count); + } + + @Test + public void testRollback() { + Assert.assertEquals(table.size(), 0); + int count = (Math.abs(new Random().nextInt()) % 255) + 100; + for (int i = 0; i < count; ++i) { + Assert.assertNull(table.put(Integer.toString(i), "rollback test")); + } + Assert.assertEquals(table.rollback(), count); + } + + @Test + public void testRollbackWithNoChanges() { + Assert.assertNull(table.put("no_changes", "will_be_deleted_soon")); + Assert.assertEquals(table.remove("no_changes"), "will_be_deleted_soon"); + Assert.assertEquals(table.rollback(), 0); + + Assert.assertNull(table.put("key", "value")); + Assert.assertEquals(table.commit(), 1); + Assert.assertEquals(table.put("key", "value_new"), "value"); + Assert.assertEquals(table.put("key", "value"), "value_new"); + Assert.assertEquals(table.rollback(), 0); + } + + @Test + public void testCommitWithNoChanges() { + Assert.assertNull(table.put("no_changes", "will_be_deleted_soon")); + Assert.assertEquals(table.remove("no_changes"), "will_be_deleted_soon"); + Assert.assertEquals(table.commit(), 0); + + Assert.assertNull(table.put("key", "value")); + Assert.assertEquals(table.commit(), 1); + Assert.assertEquals(table.put("key", "value_new"), "value"); + Assert.assertEquals(table.put("key", "value"), "value_new"); + Assert.assertEquals(table.commit(), 0); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyKey() { + table.put(" ", "empty_key"); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyValue() { + table.put("empty_value", " "); + } + + @Test(expected = IllegalArgumentException.class) + public void testNullValue() { + table.put("null_value", null); + } + + @Test + public void testWorkWithTable() { + Assert.assertNull(table.put("work", "with")); + Assert.assertEquals(table.get("work"), "with"); + Assert.assertEquals(table.remove("work"), "with"); + Assert.assertEquals(table.remove("work"), null); + Assert.assertEquals(table.commit(), 0); + Assert.assertEquals(table.rollback(), 0); + Assert.assertEquals(table.size(), 0); + } + + @Test + public void testCommitRollback() { + Assert.assertNull(table.put("commit", "rollback")); + Assert.assertEquals(table.get("commit"), "rollback"); + Assert.assertEquals(table.rollback(), 1); + Assert.assertNull(table.get("commit")); + Assert.assertNull(table.put("commit", "rollback")); + Assert.assertEquals(table.get("commit"), "rollback"); + Assert.assertEquals(table.commit(), 1); + Assert.assertEquals(table.remove("commit"), "rollback"); + Assert.assertNull(table.put("commit", "rollback1")); + Assert.assertEquals(table.commit(), 1); + Assert.assertEquals(table.get("commit"), "rollback1"); + } + + @Test + public void testList() { + Assert.assertEquals(table.list().size(), 0); + table.put("14", "88"); + table.put("22", "8"); + table.put("42", "42"); + List actual = table.list(); + Set expected = new HashSet(3); + expected.add("14"); + expected.add("22"); + expected.add("42"); + for (String s : actual) { + Assert.assertTrue(expected.contains(s)); + } + } +} From afbee19d32c21e272b26f00e91044857a299fa92 Mon Sep 17 00:00:00 2001 From: taftafa Date: Sat, 13 Dec 2014 01:23:43 +0400 Subject: [PATCH 04/13] Checkslyle... --- src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java index ea6fc6456..4c3174a46 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java @@ -271,8 +271,8 @@ public String remove(final String keyStr) { public int getNewKeys() { int result = 0; for (Node node : data) { - if ((node.getStatus() == NEW_NODE) || (node.getStatus() == MODIFIED_NODE) || - ((node.getStatus() == DELETED_NODE) && (node.old))) { + if ((node.getStatus() == NEW_NODE) || (node.getStatus() == MODIFIED_NODE) + || ((node.getStatus() == DELETED_NODE) && (node.old))) { ++result; } } From b3c694636ec367a10410462be40428ee1184cdcf Mon Sep 17 00:00:00 2001 From: taftafa Date: Sat, 20 Dec 2014 22:32:50 +0400 Subject: [PATCH 05/13] Fixed JUnit. --- .../fivt/students/kotsurba/junit/DataBaseFile.java | 1 + .../fivt/students/kotsurba/junit/DataBaseTable.java | 2 +- .../kotsurba/junit/tests/MyTableProviderFactoryTest.java | 9 +++++++-- .../kotsurba/junit/tests/MyTableProviderTest.java | 6 +++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java index 4c3174a46..be3ecfcac 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java @@ -290,6 +290,7 @@ public int getSize() { } public List getAllKeys() { + List result = new ArrayList(); for (Node node : data) { if (node.getStatus() != DELETED_NODE) { diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java index f28669afa..f2eae3e60 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java @@ -36,7 +36,7 @@ private void checkName(final String name) { if (name.matches("[" + '"' + "'\\/:/*/?//|/.\\\\]+") || name.contains(File.separator) || name.contains(".")) { - throw new RuntimeException("Wrong symbols in name!"); + throw new IllegalArgumentException("Wrong symbols in name!"); } } diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java index 08ef49673..60a69cd1c 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderFactoryTest.java @@ -8,18 +8,23 @@ import java.io.IOException; public class MyTableProviderFactoryTest { + TableProviderFactory factory; + @Rule public TemporaryFolder folder = new TemporaryFolder(); + @Before + public void before() throws IOException { + factory = new MyTableProviderFactory(); + } + @Test(expected = IllegalArgumentException.class) public void testCreateNull() { - TableProviderFactory factory = new MyTableProviderFactory(); factory.create(null); } @Test public void testCreateNotNull() throws IOException { - TableProviderFactory factory = new MyTableProviderFactory(); Assert.assertNotNull(factory.create(folder.newFolder("folder").getCanonicalPath())); } } diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java index 89621479f..a1f8eb4b9 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableProviderTest.java @@ -39,17 +39,17 @@ public void testRemoveNonExistingTable() { provider.removeTable("non_existing_table"); } - @Test(expected = RuntimeException.class) + @Test(expected = IllegalArgumentException.class) public void testGetTableWithWrongName() { provider.getTable(".." + File.separator + "database"); } - @Test(expected = RuntimeException.class) + @Test(expected = IllegalArgumentException.class) public void testCreateTableWithWrongName() { provider.createTable(".." + File.separator + "database"); } - @Test(expected = RuntimeException.class) + @Test(expected = IllegalArgumentException.class) public void testUseTableWithWrongName() { provider.removeTable(".." + File.separator + "database"); } From a16c20ea89f62320f143cc409c740dfe4d0ecde5 Mon Sep 17 00:00:00 2001 From: taftafa Date: Mon, 22 Dec 2014 00:16:21 +0400 Subject: [PATCH 06/13] Constant fixed. --- .../students/kotsurba/junit/DataBase.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java index b438e4ea6..3cd678204 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java @@ -12,14 +12,17 @@ public final class DataBase implements Table { private String dataBaseDirectory; private DataBaseFile[] files; + public static final int DIRECTORY_COUNT = 16; + public static final int FILES_COUNT = 16; + public final class DirFile { private int nDir; private int nFile; public DirFile(int key) { key = Math.abs(key); - nDir = key % 16; - nFile = (key / 16) % 16; + nDir = key % DIRECTORY_COUNT; + nFile = (key / DIRECTORY_COUNT) % FILES_COUNT; } public DirFile(final int newDir, final int newFile) { @@ -36,7 +39,7 @@ private String getNFile() { } public int getId() { - return nDir * 16 + nFile; + return nDir * DIRECTORY_COUNT + nFile; } } @@ -44,7 +47,7 @@ public DataBase(final String dbDirectory) { name = new File(dbDirectory).getName(); dataBaseDirectory = dbDirectory; isCorrect(); - files = new DataBaseFile[256]; + files = new DataBaseFile[DIRECTORY_COUNT * FILES_COUNT]; loadFiles(); } @@ -62,7 +65,7 @@ private void checkNames(final String[] dirs, final String secondName) { throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dir); } - if ((firstName < 0) || firstName > 15) { + if ((firstName < 0) || firstName > FILES_COUNT - 1) { throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dir); } } @@ -111,8 +114,8 @@ private String getFullName(final DirFile node) { } public void loadFiles() { - for (int i = 0; i < 16; ++i) { - for (int j = 0; j < 16; ++j) { + for (int i = 0; i < DIRECTORY_COUNT; ++i) { + for (int j = 0; j < FILES_COUNT; ++j) { DirFile node = new DirFile(i, j); DataBaseFile file = new DataBaseFile(getFullName(node), node.nDir, node.nFile); files[node.getId()] = file; @@ -127,8 +130,8 @@ private void checkKey(final String key) { } public void drop() { - for (byte i = 0; i < 16; ++i) { - for (byte j = 0; j < 16; ++j) { + for (byte i = 0; i < DIRECTORY_COUNT; ++i) { + for (byte j = 0; j < FILES_COUNT; ++j) { File file = new File(getFullName(new DirFile(i, j))); if (file.exists()) { if (!file.delete()) { @@ -173,7 +176,7 @@ public String remove(final String keyStr) { @Override public int commit() { int allNew = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allNew += files[i].getNewKeys(); files[i].commit(); } @@ -183,7 +186,7 @@ public int commit() { @Override public int size() { int allSize = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allSize += files[i].getSize(); } return allSize; @@ -192,7 +195,7 @@ public int size() { @Override public int rollback() { int allCanceled = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allCanceled += files[i].getNewKeys(); files[i].rollback(); } @@ -201,7 +204,7 @@ public int rollback() { public int getNewKeys() { int allNewSize = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allNewSize += files[i].getNewKeys(); } return allNewSize; From 325257a0a302f899a20ba2fd5309f06cc6cfaab5 Mon Sep 17 00:00:00 2001 From: taftafa Date: Tue, 23 Dec 2014 00:29:03 +0400 Subject: [PATCH 07/13] Fixed JUnit. --- src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java | 6 ++---- .../fivt/students/kotsurba/junit/DataBaseFile.java | 9 ++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java index 3cd678204..6e9164f9d 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBase.java @@ -212,13 +212,11 @@ public int getNewKeys() { @Override public List list() { - List result = new ArrayList(); + List result = new ArrayList<>(); for (DataBaseFile dbf : files) { if (dbf.getSize() != 0) { List ans = dbf.getAllKeys(); - for (String x : ans) { - result.add(x); - } + result.addAll(ans); } } return result; diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java index be3ecfcac..9240d4d2e 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseFile.java @@ -96,10 +96,10 @@ public void remove() { } - protected final String fileName; - protected File file; + private final String fileName; + private File file; private File dir; - protected List data; + private List data; private int fileNumber; private int direcotryNumber; @@ -290,8 +290,7 @@ public int getSize() { } public List getAllKeys() { - - List result = new ArrayList(); + List result = new ArrayList<>(); for (Node node : data) { if (node.getStatus() != DELETED_NODE) { result.add(new String(node.key)); From 973c215318c2599319202ebeaebe15b2767b1ea2 Mon Sep 17 00:00:00 2001 From: taftafa Date: Wed, 24 Dec 2014 00:39:27 +0400 Subject: [PATCH 08/13] Storeable --- .../students/kotsurba/storeable/Context.java | 21 ++ .../students/kotsurba/storeable/DataBase.java | 288 +++++++++++++++ .../kotsurba/storeable/DataBaseException.java | 7 + .../kotsurba/storeable/DataBaseFile.java | 328 ++++++++++++++++++ .../kotsurba/storeable/DataBaseTable.java | 159 +++++++++ .../storeable/DataBaseWrongFileFormat.java | 7 + .../students/kotsurba/storeable/DbMain.java | 109 ++++++ .../storeable/MultiDataBaseException.java | 8 + .../kotsurba/storeable/MySignature.java | 106 ++++++ .../kotsurba/storeable/MyStoreable.java | 227 ++++++++++++ .../storeable/MyTableProviderFactory.java | 31 ++ .../kotsurba/storeable/ShellCreateTable.java | 42 +++ .../kotsurba/storeable/ShellDbCommit.java | 29 ++ .../kotsurba/storeable/ShellDbGet.java | 30 ++ .../kotsurba/storeable/ShellDbList.java | 34 ++ .../kotsurba/storeable/ShellDbPut.java | 50 +++ .../kotsurba/storeable/ShellDbRemove.java | 27 ++ .../kotsurba/storeable/ShellDbRollback.java | 23 ++ .../kotsurba/storeable/ShellDbShow.java | 28 ++ .../kotsurba/storeable/ShellDbSize.java | 23 ++ .../kotsurba/storeable/ShellDropTable.java | 31 ++ .../kotsurba/storeable/ShellExit.java | 25 ++ .../storeable/ShellExitException.java | 7 + .../kotsurba/storeable/ShellUseTable.java | 33 ++ .../kotsurba/storeable/WorkWithJSON.java | 54 +++ .../storeable/tests/MyStoreableTest.java | 172 +++++++++ .../tests/MyTableProviderFactoryTest.java | 31 ++ .../storeable/tests/MyTableProviderTest.java | 69 ++++ .../kotsurba/storeable/tests/MyTableTest.java | 195 +++++++++++ 29 files changed, 2194 insertions(+) create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseWrongFileFormat.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/MultiDataBaseException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/MySignature.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/MyStoreable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyStoreableTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderFactoryTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java new file mode 100644 index 000000000..c67a4d0ed --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java @@ -0,0 +1,21 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.storage.structured.TableProvider; + +public class Context { + public TableProvider provider; + public Table table; + + public Context(TableProvider newProvider) { + provider = newProvider; + table = null; + } + + public int getChanges() { + if (table != null) { + return ((DataBase) table).getNewKeys(); + } + return 0; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java new file mode 100644 index 000000000..65b126ae2 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java @@ -0,0 +1,288 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.storage.structured.TableProvider; + + +public final class DataBase implements Table { + + private String name; + private String dataBaseDirectory; + private DataBaseFile[] files; + private TableProvider provider; + private List> types; + + public static final int DIRECTORY_COUNT = 16; + public static final int FILES_COUNT = 16; + + public final class DirFile { + private int nDir; + private int nFile; + + public DirFile(int key) { + key = Math.abs(key); + nDir = key % DIRECTORY_COUNT; + nFile = (key / DIRECTORY_COUNT) % FILES_COUNT; + } + + public DirFile(final int newDir, final int newFile) { + nDir = newDir; + nFile = newFile; + } + + private String getNDirectory() { + return Integer.toString(nDir) + ".dir"; + } + + private String getNFile() { + return Integer.toString(nFile) + ".dat"; + } + + public int getId() { + return nDir * DIRECTORY_COUNT + nFile; + } + } + + public DataBase(final String dbDirectory, final TableProvider newProvider, final List> newTypes) + throws IOException { + name = new File(dbDirectory).getName(); + dataBaseDirectory = dbDirectory; + provider = newProvider; + + if (newTypes != null) { + types = newTypes; + MySignature.setSignature(dataBaseDirectory, types); + } else { + types = MySignature.getSignature(dataBaseDirectory); + } + + isCorrect(); + files = new DataBaseFile[256]; + loadFiles(); + } + + private void checkNames(final String[] dirs, final String secondName) { + for (int i = 0; i < dirs.length; ++i) { + if (dirs[i].equals("signature.tsv")) { + continue; + } + String[] name = dirs[i].split("\\."); + if (name.length != 2 || !name[1].equals(secondName)) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file in path " + dirs[i]); + } + + int firstName; + try { + firstName = Integer.parseInt(name[0]); + } catch (NumberFormatException e) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dirs[i]); + } + + if ((firstName < 0) || firstName > (FILES_COUNT - 1)) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dirs[i]); + } + } + } + + private void isCorrectDirectory(final String dirName) { + File file = new File(dirName); + if (file.isFile()) { + throw new MultiDataBaseException(dirName + " isn't a directory!"); + } + String[] dirs = file.list(); + checkNames(dirs, "dat"); + for (int i = 0; i < dirs.length; ++i) { + if (new File(dirName, dirs[i]).isDirectory()) { + throw new MultiDataBaseException(dirName + File.separator + dirs[i] + " isn't a file!"); + } + } + } + + private void isCorrect() { + File file = new File(dataBaseDirectory); + if (file.isFile()) { + throw new MultiDataBaseException(dataBaseDirectory + " isn't directory!"); + } + + String[] dirs = file.list(); + checkNames(dirs, "dir"); + for (int i = 0; i < dirs.length; ++i) { + if (!dirs[i].equals("signature.tsv")) { + isCorrectDirectory(dataBaseDirectory + File.separator + dirs[i]); + } + } + } + + private void tryDeleteDirectory(final String name) { + File file = new File(dataBaseDirectory + File.separator + name); + if (file.exists()) { + if (file.list().length == 0) { + if (!file.delete()) { + throw new DataBaseException("Cannot delete a directory!"); + } + } + } + } + + private String getFullName(final DirFile node) { + return dataBaseDirectory + File.separator + node.getNDirectory() + File.separator + node.getNFile(); + } + + public void loadFiles() throws IOException { + for (int i = 0; i < DIRECTORY_COUNT; ++i) { + for (int j = 0; j < FILES_COUNT; ++j) { + DirFile node = new DirFile(i, j); + DataBaseFile file = new DataBaseFile(getFullName(node), node.nDir, node.nFile, this, provider); + files[node.getId()] = file; + } + } + } + + boolean containsWhitespace(String s) { + for (int i = 0; i < s.length(); ++i) { + if (Character.isWhitespace(s.charAt(i))) { + return true; + } + } + return false; + } + + private void checkKey(final String key) { + if ((key == null) || (key.trim().length() == 0) || (containsWhitespace(key))) { + throw new IllegalArgumentException("Wrong key!"); + } + } + + public void drop() { + for (byte i = 0; i < DIRECTORY_COUNT; ++i) { + for (byte j = 0; j < FILES_COUNT; ++j) { + File file = new File(getFullName(new DirFile(i, j))); + if (file.exists()) { + if (!file.delete()) { + throw new DataBaseException("Cannot delete a file!"); + } + } + } + tryDeleteDirectory(Integer.toString(i) + ".dir"); + } + if (!new File(dataBaseDirectory, "signature.tsv").delete()) { + throw new DataBaseException("Cannot delete a file!"); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public Storeable put(final String keyStr, final Storeable storeableValue) { + checkKey(keyStr); + if (storeableValue == null) { + throw new IllegalArgumentException("Wrong put value = null!"); + } + DirFile node = new DirFile(keyStr.getBytes()[0]); + DataBaseFile file = files[node.getId()]; + String value = WorkWithJSON.serialize(this, storeableValue); + String result = file.put(keyStr, value); + return WorkWithJSON.deserialize(this, result); + } + + @Override + public Storeable get(final String keyStr) { + checkKey(keyStr); + DirFile node = new DirFile(keyStr.getBytes()[0]); + String result = files[node.getId()].get(keyStr); + return WorkWithJSON.deserialize(this, result); + } + + @Override + public Storeable remove(final String keyStr) { + checkKey(keyStr); + DirFile node = new DirFile(keyStr.getBytes()[0]); + DataBaseFile file = files[node.getId()]; + String result = file.remove(keyStr); + return WorkWithJSON.deserialize(this, result); + } + + @Override + public int commit() { + int allNew = 0; + for (int i = 0; i < 256; ++i) { + allNew += files[i].getNewKeys(); + files[i].commit(); + } + return allNew; + } + + @Override + public int size() { + int allSize = 0; + for (int i = 0; i < 256; ++i) { + allSize += files[i].getSize(); + } + return allSize; + } + + @Override + public List list() { + List result = new ArrayList(); + for (DataBaseFile dbf : files) { + if (dbf.getSize() != 0) { + List ans = dbf.getAllKeys(); + for (String x : ans) { + result.add(x); + } + } + } + return result; + } + + + @Override + public int rollback() { + int allCanceled = 0; + for (int i = 0; i < 256; ++i) { + allCanceled += files[i].getNewKeys(); + files[i].rollback(); + } + return allCanceled; + } + + @Override + public int getNumberOfUncommittedChanges() { + return getNewKeys(); + } + + @Override + public int getColumnsCount() { + return types.size(); + } + + public int getNewKeys() { + int allNewSize = 0; + for (int i = 0; i < 256; ++i) { + allNewSize += files[i].getNewKeys(); + } + return allNewSize; + } + + @Override + public Class getColumnType(int columnIndex) throws IndexOutOfBoundsException { + if ((columnIndex < 0) || (columnIndex >= types.size())) { + throw new IndexOutOfBoundsException("getColumnType: columnIndex is wrong"); + } + return types.get(columnIndex); + } + + public Storeable putStoreable(String keyStr, String valueStr) throws ParseException { + return put(keyStr, provider.deserialize(this, valueStr)); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java new file mode 100644 index 000000000..a73a6cd0f --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +public class DataBaseException extends Error { + public DataBaseException(final String message) { + super(message); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java new file mode 100644 index 000000000..83d3c1aca --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java @@ -0,0 +1,328 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + + +import ru.fizteh.fivt.storage.structured.TableProvider; + +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.io.File; +import java.io.FileNotFoundException; + +public class DataBaseFile { + + static final byte OLD_NODE = 1; + static final byte NEW_NODE = 2; + static final byte MODIFIED_NODE = 3; + static final byte DELETED_NODE = 4; + + + public final class Node { + private byte status; + private boolean old; + private byte[] key; + private byte[] value; + private byte[] oldValue; + + public int getZeroByte() { + return Math.abs(key[0]); + } + + public Node(final byte[] newKey, final byte[] newValue) { + status = NEW_NODE; + key = newKey; + value = newValue; + oldValue = null; + old = false; + } + + public Node(final RandomAccessFile inputFile) throws IOException { + try { + int keyLength = inputFile.readInt(); + int valueLength = inputFile.readInt(); + if ((keyLength <= 0) || (valueLength <= 0)) { + throw new DataBaseWrongFileFormat("Wrong file format! " + file.getName()); + } + try { + key = new byte[keyLength]; + value = new byte[valueLength]; + } catch (OutOfMemoryError e) { + throw new DataBaseWrongFileFormat("Some key or value are too large in " + file.getName()); + } + inputFile.read(key); + inputFile.read(value); + setOld(); + } catch (Exception e) { + throw new DataBaseWrongFileFormat("Wrong file format! " + file.getName()); + } + } + + public void setOld() { + status = OLD_NODE; + old = true; + oldValue = value; + } + + public void setKey(final byte[] newKey) { + key = newKey; + } + + public void setValue(final byte[] newValue) { + status = MODIFIED_NODE; + if ((oldValue != null) && (Arrays.equals(oldValue, newValue))) { + status = OLD_NODE; + } + value = newValue; + } + + public void write(final RandomAccessFile outputFile) throws IOException { + if (status == DELETED_NODE) { + return; + } + outputFile.writeInt(key.length); + outputFile.writeInt(value.length); + outputFile.write(key); + outputFile.write(value); + } + + public byte getStatus() { + return status; + } + + public void setStatus(byte newStatus) { + status = newStatus; + } + + public void remove() { + value = null; + status = DELETED_NODE; + } + + } + + protected final String fileName; + protected File file; + private File dir; + protected List data; + private int fileNumber; + private int direcotryNumber; + private DataBase table; + private TableProvider provider; + + public DataBaseFile(final String newFileName, final int newDirectoryNumber, final int newFileNumber, + DataBase newTable, TableProvider newProvider) throws IOException { + table = newTable; + provider = newProvider; + fileName = newFileName; + file = new File(fileName); + data = new ArrayList(); + fileNumber = newFileNumber; + direcotryNumber = newDirectoryNumber; + String path = file.getParent(); + dir = new File(path); + load(); + check(); + } + + public boolean check() throws IOException { + for (Node node : data) { + if (!((node.getZeroByte() % 16 == direcotryNumber) && ((node.getZeroByte() / 16) % 16 == fileNumber))) { + throw new IOException("Wrong file format key[0] = " + String.valueOf(node.getZeroByte()) + + " in file " + fileName); + } + try { + provider.deserialize(table, new String(node.value)); + } catch (ParseException e) { + throw new IOException("Invalid file format! (parse exception error!)"); + } + } + return true; + } + + private void load() { + try { + if (dir.exists() && dir.list().length == 0) { + throw new IOException("Empty dir!"); + } + if (!dir.exists() || !file.exists()) { + return; + } + try (RandomAccessFile inputFile = new RandomAccessFile(fileName, "rw")) { + while (inputFile.getFilePointer() < inputFile.length() - 1) { + data.add(new Node(inputFile)); + } + } + if (data.size() == 0) { + throw new IOException("Empty file!"); + } + } catch (FileNotFoundException e) { + throw new DataBaseException("File not found!"); + } catch (IOException e) { + throw new DataBaseException("File load error!"); + } + } + + public void createPath() { + if (dir.exists()) { + return; + } + + if (!dir.mkdir()) { + throw new DataBaseException("Cannot create directory!"); + } + } + + public void deletePath() { + if (!dir.exists()) { + return; + } + + if (dir.list().length != 0) { + return; + } + + if (!dir.delete()) { + throw new DataBaseException("Cannot delete a directory!"); + } + } + + public void save() { + try { + if (getSize() == 0) { + if ((file.exists()) && (!file.delete())) { + throw new DataBaseException("Cannot delete a file!"); + } + deletePath(); + } else { + createPath(); + if (!file.exists()) { + if (!file.createNewFile()) { + throw new DataBaseException("Cannot create a file " + fileName); + } + } + try (RandomAccessFile outputFile = new RandomAccessFile(fileName, "rw")) { + for (Node node : data) { + node.write(outputFile); + } + outputFile.setLength(outputFile.getFilePointer()); + } + } + } catch (FileNotFoundException e) { + throw new DataBaseException("File save error!"); + } catch (IOException e) { + throw new DataBaseException("Write to file error!"); + } + } + + + private int search(final byte[] key) { + for (int i = 0; i < data.size(); ++i) { + if (Arrays.equals(data.get(i).key, key)) { + return i; + } + } + return -1; + } + + public String put(final String keyStr, final String valueStr) { + byte[] key = keyStr.getBytes(StandardCharsets.UTF_8); + byte[] value = valueStr.getBytes(StandardCharsets.UTF_8); + + int index = search(key); + if (index == -1) { + data.add(new Node(key, value)); + return null; + } else { + int status = data.get(index).status; + String result = null; + if (status != DELETED_NODE) { + result = new String(data.get(index).value); + } + data.get(index).setValue(value); + return result; + } + } + + public String get(final String keyStr) { + byte[] key = keyStr.getBytes(StandardCharsets.UTF_8); + int index = search(key); + if (index != -1) { + if (data.get(index).status == DELETED_NODE) { + return null; + } + return new String(data.get(index).value); + } else { + return null; + } + } + + public String remove(final String keyStr) { + byte[] key = keyStr.getBytes(StandardCharsets.UTF_8); + int index = search(key); + if (index == -1) { + return null; + } else { + String result; + if (data.get(index).status == DELETED_NODE) { + result = null; + } else { + result = new String(data.get(index).value); + } + data.get(index).remove(); + return result; + } + } + + public int getNewKeys() { + int result = 0; + for (Node node : data) { + if ((node.getStatus() == NEW_NODE) || (node.getStatus() == MODIFIED_NODE) + || ((node.getStatus() == DELETED_NODE) && (node.old))) { + ++result; + } + } + return result; + } + + public int getSize() { + int result = 0; + for (Node node : data) { + if (node.getStatus() != DELETED_NODE) { + ++result; + } + } + return result; + } + + public List getAllKeys() { + + List result = new ArrayList(); + for (Node node : data) { + if (node.getStatus() != DELETED_NODE) { + result.add(new String(node.key)); + } + } + return result; + } + + public void commit() { + save(); + for (int i = 0; i < data.size(); ) { + if (data.get(i).getStatus() == DELETED_NODE) { + data.remove(i); + } else { + data.get(i).setOld(); + ++i; + } + } + } + + public void rollback() { + data.clear(); + load(); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java new file mode 100644 index 000000000..72d05dd09 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java @@ -0,0 +1,159 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONException; +import ru.fizteh.fivt.storage.structured.ColumnFormatException; +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.storage.structured.TableProvider; + +public final class DataBaseTable implements TableProvider { + private String tableDir; + private Map tableInUse; + + public DataBaseTable(String newTableDir) { + tableDir = newTableDir; + tableInUse = new HashMap(); + } + + private void checkName(final String name) { + if ((name == null) || name.trim().length() == 0) { + throw new IllegalArgumentException("Cannot create table! Wrong name!"); + } + + if (name.matches("[" + '"' + "'\\/:/*/?//|/.\\\\]+") || name.contains(File.separator) + || name.contains(".")) { + throw new RuntimeException("Wrong symbols in name!"); + } + } + + @Override + public Table createTable(final String tableName, List> columnTypes) throws IOException { + checkName(tableName); + String fullPath = tableDir + File.separator + tableName; + + if (columnTypes == null || columnTypes.size() == 0) { + throw new IllegalArgumentException("wrong type (null)"); + } + + File file = new File(fullPath); + + if (file.exists()) { + return null; + } + + if (!file.mkdir()) { + throw new MultiDataBaseException("Cannot create table " + tableName); + } + + DataBase table = new DataBase(fullPath, this, columnTypes); + tableInUse.put(tableName, table); + return table; + } + + @Override + public void removeTable(final String tableName) throws IOException { + checkName(tableName); + String fullPath = tableDir + File.separator + tableName; + + File file = new File(fullPath); + if (!file.exists()) { + throw new IllegalStateException("Table not exist already!"); + } + + if (!tableInUse.containsKey(tableName)) { + DataBase base = new DataBase(tableName, this, null); + base.drop(); + } else { + tableInUse.get(tableName).drop(); + tableInUse.remove(tableName); + } + if (!file.delete()) { + throw new DataBaseException("Cannot delete a file " + tableName); + } + } + + @Override + public Table getTable(String tableName) { + checkName(tableName); + String fullPath = tableDir + File.separator + tableName; + + File file = new File(fullPath); + if ((!file.exists()) || (file.isFile())) { + return null; + } + if (tableInUse.containsKey(tableName)) { + return tableInUse.get(tableName); + } else { + try { + DataBase table = new DataBase(fullPath, this, null); + tableInUse.put(tableName, table); + return table; + } catch (IOException e) { + throw new DataBaseException(e.getMessage()); + } + } + } + + @Override + public Storeable deserialize(Table table, String value) throws ParseException { + JSONArray json = null; + try { + json = new JSONArray(value); + } catch (JSONException e) { + throw new ParseException("Can't parse.", 0); + } + List values = new ArrayList<>(); + for (int i = 0; i < json.length(); ++i) { + try { + values.add(json.get(i)); + } catch (JSONException e) { + throw new ParseException("Can't parse.", 0); + } + } + + Storeable storeable; + try { + storeable = createFor(table, values); + } catch (IndexOutOfBoundsException e) { + throw new ParseException("Invalud number of arguments!", 0); + } catch (ColumnFormatException e) { + throw new ParseException(e.getMessage(), 0); + } + + return storeable; + } + + @Override + public String serialize(Table table, Storeable value) throws ColumnFormatException { + return WorkWithJSON.serialize(table, value); + } + + @Override + public Storeable createFor(Table table) { + return new MyStoreable(table); + } + + @Override + public Storeable createFor(Table table, List values) throws ColumnFormatException, IndexOutOfBoundsException { + return new MyStoreable(table, values); + } + + @Override + public List getTableNames() { + List result = new ArrayList(); + for (String str : new File(tableDir).list()) { + result.add(str); + } + return result; + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseWrongFileFormat.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseWrongFileFormat.java new file mode 100644 index 000000000..b44b631ab --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseWrongFileFormat.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +public class DataBaseWrongFileFormat extends Error { + public DataBaseWrongFileFormat(final String message) { + super(message); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java new file mode 100644 index 000000000..cb9539cfc --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java @@ -0,0 +1,109 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import java.io.IOException; +import java.util.Scanner; + +import ru.fizteh.fivt.storage.structured.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.Shell; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandParser; +import ru.fizteh.fivt.students.kotsurba.shell.ShellMain; + +public class DbMain { + private static Shell shell; + + private static void checkDbDir() { + if (!System.getProperties().containsKey("fizteh.db.dir")) { + System.err.println("Please set database directory!"); + System.err.println("-Dfizteh.db.dir="); + System.exit(1); + } + } + + private static void initShell() { + try { + shell = new Shell(); + + TableProviderFactory factory = new MyTableProviderFactory(); + Context context = new Context(factory.create(System.getProperty("fizteh.db.dir"))); + + shell.addCommand(new ShellDbPut(context)); + shell.addCommand(new ShellExit(context)); + shell.addCommand(new ShellDbGet(context)); + shell.addCommand(new ShellDbRemove(context)); + shell.addCommand(new ShellCreateTable(context)); + shell.addCommand(new ShellDropTable(context)); + shell.addCommand(new ShellUseTable(context)); + shell.addCommand(new ShellDbSize(context)); + shell.addCommand(new ShellDbCommit(context)); + shell.addCommand(new ShellDbRollback(context)); + shell.addCommand(new ShellDbList(context)); + shell.addCommand(new ShellDbShow(context)); + + } catch (IOException e) { + System.out.println("init shell failed!"); + System.exit(1); + } + } + + private static void packetRun(final String[] args) { + try { + CommandParser parser = new CommandParser(args); + while (!parser.isEmpty()) { + shell.executeCommand(parser.getCommand()); + } + } catch (InvalidCommandException | MultiDataBaseException | DataBaseWrongFileFormat | RuntimeException e) { + System.err.println(e.getMessage()); + } + } + + private static void interactiveRun() { + Scanner scanner = new Scanner(System.in); + System.out.print(" $ "); + while (true) { + try { + if (!scanner.hasNextLine()) { + throw new ShellExitException("Ctrl + D exit!"); + } + + String command = scanner.nextLine(); + + if (ShellMain.hasTerminalSymbol(command)) { + throw new ShellExitException("Ctrl + D exit or EOF!"); + } + + CommandParser parser = new CommandParser(command); + if (!parser.isEmpty()) { + shell.executeCommand(parser.getCommand()); + } + } catch (MultiDataBaseException | DataBaseWrongFileFormat | InvalidCommandException + | RuntimeException e) { + System.err.println(e.getMessage()); + } finally { + System.out.print(" $ "); + } + } + } + + public static void main(final String[] args) { + try { + checkDbDir(); + initShell(); + + if (args.length > 0) { + packetRun(args); + } else { + interactiveRun(); + } + + } catch (DataBaseException e) { + System.err.println(e.getMessage()); + System.exit(1); + } catch (ShellExitException e) { + System.exit(0); + } finally { + System.exit(0); + } + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/MultiDataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/MultiDataBaseException.java new file mode 100644 index 000000000..f739528f1 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/MultiDataBaseException.java @@ -0,0 +1,8 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +public class MultiDataBaseException extends Error { + public MultiDataBaseException(final String message) { + super(message); + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/MySignature.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/MySignature.java new file mode 100644 index 000000000..b5ae38c5d --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/MySignature.java @@ -0,0 +1,106 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class MySignature { + static final String[] TYPES = {"int", "long", "byte", "float", "double", "boolean", "String"}; + static final Class[] CLASSES = {Integer.class, Long.class, Byte.class, Float.class, + Double.class, Boolean.class, String.class}; + + + public static List> getSignature(final String dir) throws IOException { + File file = new File(dir, "signature.tsv"); + if (!file.exists()) { + throw new IOException("Cannot find file:" + file.getCanonicalPath()); + } + + StringBuilder builder = new StringBuilder(); + + try (Scanner input = new Scanner(file)) { + if (!input.hasNext()) { + throw new IOException("Empty signature: " + file.getCanonicalPath()); + } + while (input.hasNext()) { + builder.append(input.next()).append(" "); + } + } + + String[] data = builder.toString().split(" "); + + List> result = new ArrayList<>(); + + if (data.length <= 0) { + throw new IOException("Empty signature: " + file.getCanonicalPath()); + } + + for (int i = 0; i < data.length; ++i) { + boolean flag = false; + for (int j = 0; j < TYPES.length; ++j) { + if (data[i].equals(TYPES[j])) { + result.add(CLASSES[j]); + flag = true; + break; + } + } + if (!flag) { + throw new IOException("Invalid type!"); + } + } + return result; + } + + public static void setSignature(final String dir, List> classesList) throws IOException { + try (PrintWriter output = new PrintWriter(new File(dir, "signature.tsv"))) { + for (int i = 0; i < classesList.size(); ++i) { + boolean flag = false; + for (int j = 0; j < CLASSES.length; ++j) { + if (CLASSES[j].equals(classesList.get(i))) { + output.write(TYPES[j]); + flag = true; + break; + } + } + if (!flag) { + throw new IllegalArgumentException("Bad TYPES!"); + } + if (i + 1 != classesList.size()) { + output.write(" "); + } + } + } + + } + + public static List> getTypes(final String str) throws IOException { + List> result = new ArrayList<>(); + byte[] s = str.trim().getBytes(); + if (!(s[0] == '(' && s[str.length() - 1] == ')')) { + throw new IOException("wrong type (no brackets)"); + } + for (int i = 1; i < str.length() - 1; ++i) { + if (s[i] == ' ') { + continue; + } + + boolean flag = false; + for (int j = 0; j < TYPES.length; ++j) { + if (new String(s, i, Math.min(TYPES[j].length(), str.length() - i)).equals(TYPES[j])) { + result.add(CLASSES[j]); + i += TYPES[j].length(); + flag = true; + break; + } + } + + if (!flag) { + throw new IOException("Cannot read type! position: " + i); + } + } + return result; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/MyStoreable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/MyStoreable.java new file mode 100644 index 000000000..b244e7b5f --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/MyStoreable.java @@ -0,0 +1,227 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import org.json.JSONObject; +import ru.fizteh.fivt.storage.structured.ColumnFormatException; +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; + +import java.util.ArrayList; +import java.util.List; + +public class MyStoreable implements Storeable { + private List> types = new ArrayList<>(); + private List values = new ArrayList<>(); + + public MyStoreable(Table table, List newValues) { + if (newValues == null) { + throw new IndexOutOfBoundsException("list of values cannot be null"); + } + if (newValues.size() != table.getColumnsCount()) { + throw new IndexOutOfBoundsException("invalid number of values"); + } + + for (int i = 0; i < newValues.size(); ++i) { + Object value = castTypes(table.getColumnType(i), newValues.get(i)); + if (value != null && value.getClass() != table.getColumnType(i)) { + throw new ColumnFormatException(newValues.get(i).toString() + " must be " + table.getColumnType(i) + + " but it is " + newValues.get(i).getClass()); + } + types.add(table.getColumnType(i)); + values.add(value); + } + } + + public MyStoreable(Table table) { + for (int i = 0; i < table.getColumnsCount(); ++i) { + types.add(table.getColumnType(i)); + values.add(null); + } + } + + + void checkBounds(int index) { + if (index < 0 || index >= types.size()) { + throw new IndexOutOfBoundsException("index out of bounds!"); + } + } + + void checkType(int index, Class value) { + if ((value != null) && (value != types.get(index))) { + throw new ColumnFormatException(); + } + } + + Object castTypes(Class type, Object value) { + if (value == null) { + return null; + } + + Class valueType = value.getClass(); + if (valueType == JSONObject.NULL.getClass() || JSONObject.NULL == value) { + return null; + } + + if (type == Integer.class) { + if (valueType == Integer.class) { + return value; + } + if (valueType == Byte.class) { + return new Integer((byte) value); + } + if (valueType == Long.class) { + long tmp = (long) value; + if (tmp <= Integer.MAX_VALUE && tmp >= Integer.MIN_VALUE) { + return (int) tmp; + } else { + throw new ColumnFormatException("Too big number for integer type: " + value.toString()); + } + } + throw new ColumnFormatException("Wrong type: " + valueType + " insted of Integer!"); + } + + if (type == Byte.class) { + if (valueType == Byte.class) { + return value; + } + if (valueType == Long.class || valueType == Integer.class) { + long tmp; + if (valueType == Long.class) { + tmp = (long) value; + } else { + tmp = (int) value; + } + if (tmp <= Byte.MAX_VALUE && tmp >= Byte.MIN_VALUE) { + return (byte) tmp; + } else { + throw new ColumnFormatException("Too big number for byte type: " + value.toString()); + } + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Byte!"); + } + + if (type == Long.class) { + if (valueType == Long.class) { + return value; + } + if (valueType == Byte.class) { + return new Long((byte) value); + } + if (valueType == Integer.class) { + return new Long((int) value); + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Long!"); + } + + if (type == Double.class) { + if (valueType == Integer.class) { + return new Double((int) value); + } + if (valueType == Byte.class) { + return new Double((byte) value); + } + if (valueType == Long.class) { + return new Double((long) value); + } + if (valueType == Float.class) { + return new Double((float) value); + } + if (valueType == Double.class) { + return value; + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Double"); + } + + if (type == Float.class) { + if (valueType == Integer.class) { + return new Float((int) value); + } + if (valueType == Byte.class) { + return new Float((byte) value); + } + if (valueType == Long.class) { + return new Float((long) value); + } + if (valueType == Double.class) { + return new Float((double) value); + } + if (value == Float.class) { + return value; + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Float"); + } + + if (type == String.class) { + return value.toString(); + } + + return value; + } + + @Override + public void setColumnAt(int columnIndex, Object value) throws ColumnFormatException, IndexOutOfBoundsException { + if (value == null || value == JSONObject.NULL) { + value = null; + } + checkBounds(columnIndex); + value = castTypes(types.get(columnIndex), value); + if (value != null) { + checkType(columnIndex, value.getClass()); + } + values.set(columnIndex, value); + } + + @Override + public Object getColumnAt(int columnIndex) throws IndexOutOfBoundsException { + checkBounds(columnIndex); + return values.get(columnIndex); + } + + @Override + public Integer getIntAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Integer.class); + return (Integer) values.get(columnIndex); + } + + @Override + public Long getLongAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Long.class); + return (long) values.get(columnIndex); + } + + @Override + public Byte getByteAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Byte.class); + return (byte) values.get(columnIndex); + } + + @Override + public Float getFloatAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Float.class); + return (float) values.get(columnIndex); + } + + @Override + public Double getDoubleAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Double.class); + return (double) values.get(columnIndex); + } + + @Override + public Boolean getBooleanAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Boolean.class); + return (boolean) values.get(columnIndex); + } + + @Override + public String getStringAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, String.class); + return (String) values.get(columnIndex); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java new file mode 100644 index 000000000..8b2857f19 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java @@ -0,0 +1,31 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.storage.structured.TableProvider; +import ru.fizteh.fivt.storage.structured.TableProviderFactory; + +import java.io.File; +import java.io.IOException; + +public class MyTableProviderFactory implements TableProviderFactory { + + @Override + public TableProvider create(String dir) throws IOException { + if (dir == null || dir.trim().equals("")) { + throw new IllegalArgumentException("Dir cannot be null"); + } + + File tableDirFile = new File(dir); + + if (!tableDirFile.exists()) { + if (!tableDirFile.mkdirs()) { + throw new IOException("Cannot create directory! " + tableDirFile.getCanonicalPath()); + } + } + + if (!tableDirFile.isDirectory()) { + throw new IllegalArgumentException("Wrong dir " + dir); + } + + return new DataBaseTable(dir); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java new file mode 100644 index 000000000..1ddd96f10 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java @@ -0,0 +1,42 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandString; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.io.IOException; + +public class ShellCreateTable extends SimpleShellCommand { + private Context context; + + public ShellCreateTable(Context newContext) { + context = newContext; + setName("create"); + setNumberOfArgs(3); + setHint("usage: create
()"); + } + + public void run() { + try { + if (context.provider.createTable(getArg(1), MySignature.getTypes(getSpacedArg(2))) != null) { + System.out.println("created"); + } else { + System.out.println(getArg(1) + " exists"); + } + } catch (IOException e) { + System.out.println("wrong type (" + e.getMessage() + ")"); + } + } + + @Override + public boolean isMyCommand(final CommandString command) { + if (name.equals(command.getArg(0))) { + if (command.length() < numberOfArgs) { + throw new InvalidCommandException("wrong type (" + name + " " + hint + ")"); + } + args = command; + return true; + } + return false; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java new file mode 100644 index 000000000..925258ea3 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java @@ -0,0 +1,29 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.io.IOException; + +public class ShellDbCommit extends SimpleShellCommand { + private Context context; + + public ShellDbCommit(final Context newContext) { + context = newContext; + setName("commit"); + setNumberOfArgs(1); + setHint("usage: commit"); + } + + @Override + public void run() { + try { + if (context.table != null) { + System.out.println(context.table.commit()); + } else { + System.out.println("no table"); + } + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java new file mode 100644 index 000000000..0f2c0ceb8 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java @@ -0,0 +1,30 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDbGet extends SimpleShellCommand { + private Context context; + + public ShellDbGet(final Context newContext) { + context = newContext; + setName("get"); + setNumberOfArgs(2); + setHint("usage: get "); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + Storeable storeable = context.table.get(getArg(1)); + if (storeable == null) { + System.out.println("not found"); + } else { + System.out.println("found"); + System.out.println(context.provider.serialize(context.table, storeable)); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java new file mode 100644 index 000000000..c4b56e8ff --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java @@ -0,0 +1,34 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.util.List; + +public final class ShellDbList extends SimpleShellCommand { + private Context context; + + public ShellDbList(final Context newContext) { + context = newContext; + setName("list"); + setNumberOfArgs(1); + setHint("usage: list"); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + List str = context.table.list(); + StringBuilder keys = new StringBuilder(); + for (String string : str) { + keys.append(string).append(", "); + } + if (keys.length() > 1) { + keys.deleteCharAt(keys.length() - 1); + keys.deleteCharAt(keys.length() - 1); + } + System.out.println(keys); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java new file mode 100644 index 000000000..a69c6f55e --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java @@ -0,0 +1,50 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandString; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.text.ParseException; + +public final class ShellDbPut extends SimpleShellCommand { + private Context context; + + public ShellDbPut(final Context newContext) { + context = newContext; + setName("put"); + setNumberOfArgs(3); + setHint("usage: put "); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + try { + Storeable storeable = ((DataBase) context.table).putStoreable(getArg(1), getSpacedArg(2)); + if (storeable == null) { + System.out.println("new"); + } else { + System.out.println("overwrite"); + System.out.println(context.provider.serialize(context.table, storeable)); + } + } catch (ParseException e) { + System.out.println("wrong type (" + e.getMessage() + ")"); + } + } + + @Override + public boolean isMyCommand(final CommandString command) { + if (name.equals(command.getArg(0))) { + if (command.length() < numberOfArgs) { + throw new InvalidCommandException(name + " " + hint); + } + args = command; + return true; + } + return false; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java new file mode 100644 index 000000000..e868a685a --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java @@ -0,0 +1,27 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public final class ShellDbRemove extends SimpleShellCommand { + private Context context; + + public ShellDbRemove(Context newContext) { + context = newContext; + setName("remove"); + setNumberOfArgs(2); + setHint("usage: remove "); + } + + @Override + public void run() { + if (context.table == null) { + System.out.println("no table"); + return; + } + if (context.table.remove(getArg(1)) == null) { + System.out.println("not found"); + } else { + System.out.println("removed"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java new file mode 100644 index 000000000..0cf56b3d0 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java @@ -0,0 +1,23 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDbRollback extends SimpleShellCommand { + private Context context; + + public ShellDbRollback(final Context newContext) { + context = newContext; + setName("rollback"); + setNumberOfArgs(1); + setHint("usage: rollback"); + } + + @Override + public void run() { + if (context.table != null) { + System.out.println(context.table.rollback()); + } else { + System.out.println("no table"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java new file mode 100644 index 000000000..d51c9a213 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java @@ -0,0 +1,28 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.io.File; +import java.util.List; + +public class ShellDbShow extends SimpleShellCommand { + private Context context; + + public ShellDbShow(Context newContext) { + context = newContext; + setName("show"); + setNumberOfArgs(2); + setHint("usage: show tables"); + } + + public void run() { + if (getArg(1).equals("tables")) { + List names = context.provider.getTableNames(); + for (String name : names) { + System.out.println(name + " " + context.provider.getTable(name).size()); + } + } else { + System.out.println("Invalid command!"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java new file mode 100644 index 000000000..91b81c0cc --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java @@ -0,0 +1,23 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellDbSize extends SimpleShellCommand { + private Context context; + + public ShellDbSize(final Context newContext) { + context = newContext; + setName("size"); + setNumberOfArgs(1); + setHint("usage: size"); + } + + @Override + public void run() { + if (context.table != null) { + System.out.println(context.table.size()); + } else { + System.out.println("no table"); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java new file mode 100644 index 000000000..466fe343e --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java @@ -0,0 +1,31 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +import java.io.IOException; + +public class ShellDropTable extends SimpleShellCommand { + private Context context; + + public ShellDropTable(Context newContext) { + context = newContext; + setName("drop"); + setNumberOfArgs(2); + setHint("usage: drop
"); + } + + public void run() { + try { + if ((context.table != null) && (context.table.getName().equals(getArg(1)))) { + context.table = null; + } + + context.provider.removeTable(getArg(1)); + System.out.println("dropped"); + } catch (IllegalStateException e) { + System.out.println(getArg(1) + " not exists"); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java new file mode 100644 index 000000000..70c0d551d --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java @@ -0,0 +1,25 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public final class ShellExit extends SimpleShellCommand { + private Context context; + + public ShellExit(final Context newContext) { + context = newContext; + setName("exit"); + setNumberOfArgs(1); + setHint("usage: exit"); + } + + @Override + public void run() { + if (context.getChanges() == 0) { + throw new ShellExitException("Exit command"); + } else { + System.out.println(context.getChanges() + " unsaved changes"); + System.out.println("Cant't exit"); + } + } + +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java new file mode 100644 index 000000000..dd1f97c6c --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +public class ShellExitException extends Error { + public ShellExitException(final String message) { + super(message); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java new file mode 100644 index 000000000..df967ff73 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java @@ -0,0 +1,33 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; + +public class ShellUseTable extends SimpleShellCommand { + private Context context; + + public ShellUseTable(Context newContext) { + context = newContext; + setName("use"); + setNumberOfArgs(2); + setHint("usage: use
"); + } + + public void run() { + if ((context.table != null) && (context.getChanges() != 0)) { + System.out.println(context.getChanges() + " unsaved changes"); + return; + } + + Table old = context.table; + context.table = context.provider.getTable(getArg(1)); + if (context.table != null) { + System.out.println("using " + getArg(1)); + } else { + context.table = old; + System.out.println(getArg(1) + " not exists"); + } + } + + +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java new file mode 100644 index 000000000..634da5aa4 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java @@ -0,0 +1,54 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import org.json.JSONArray; +import org.json.JSONException; +import ru.fizteh.fivt.storage.structured.ColumnFormatException; +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; + +public class WorkWithJSON { + + public static String serialize(Table table, Storeable value) throws ColumnFormatException { + + try { + value.getColumnAt(table.getColumnsCount()); + throw new ColumnFormatException("Too many columns!"); + } catch (IndexOutOfBoundsException e) { + } + + JSONArray array = new JSONArray(); + for (int i = 0; i < table.getColumnsCount(); ++i) { + try { + if (value.getColumnAt(i) == null || value.getColumnAt(i).getClass() == table.getColumnType(i)) { + array.put(value.getColumnAt(i)); + } else { + throw new ColumnFormatException("Column " + i + " has wrong type!"); + } + } catch (IndexOutOfBoundsException e) { + throw new ColumnFormatException("Too few columns!"); + } + } + return array.toString(); + } + + public static Storeable deserialize(Table table, String value) { + if (value == null) { + return null; + } + Storeable result = new MyStoreable(table); + JSONArray array = null; + try { + array = new JSONArray(value); + } catch (JSONException e) { + throw new IllegalArgumentException("can't deserialize"); + } + for (Integer i = 0; i < array.length(); ++i) { + try { + result.setColumnAt(i, array.get(i)); + } catch (JSONException e) { + throw new IllegalArgumentException("can't deserialize"); + } + } + return result; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyStoreableTest.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyStoreableTest.java new file mode 100644 index 000000000..f413511ad --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyStoreableTest.java @@ -0,0 +1,172 @@ +package ru.fizteh.fivt.students.kotsurba.storeable.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.*; +import ru.fizteh.fivt.students.kotsurba.storeable.MyTableProviderFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +public class MyStoreableTest { + static Table table; + static TableProviderFactory factory; + static TableProvider provider; + static List> types; + static Storeable s; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void beforeTest() throws IOException { + provider = factory.create(folder.newFolder("folder").getCanonicalPath()); + types = new ArrayList<>(); + types.add(Integer.class); + types.add(String.class); + types.add(Byte.class); + types.add(Long.class); + types.add(Double.class); + types.add(Float.class); + types.add(Boolean.class); + table = provider.createTable("simple", types); + s = provider.createFor(table); + s.setColumnAt(0, 1); + s.setColumnAt(1, "1"); + s.setColumnAt(2, 1); + s.setColumnAt(3, 1); + s.setColumnAt(4, 1.11); + s.setColumnAt(5, 1.2); + s.setColumnAt(6, true); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testBoundsException() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(122, "12"); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testBoundsExceptionMore() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(-2, "44"); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatException() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, true); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionMore() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, "asdasd"); + storeable.getIntAt(0); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionLongInt() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(1, new Long("100000000000")); + storeable.getIntAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionDouble() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(1, new Double(0.0001)); + storeable.getIntAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionFloat() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(1, new Float(0.0201)); + storeable.getIntAt(1); + } + + @Test + public void testSetByteAtIntColumn() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, (byte) 11); + storeable.getIntAt(0); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionIntYo() { + s.getIntAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionByte() { + s.getByteAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionLong() { + s.getLongAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionDoubleYo() { + s.getDoubleAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionFloatYo() { + s.getFloatAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionString() { + s.getStringAt(0); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionBoolean() { + s.getBooleanAt(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionInt() { + s.getIntAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionString() { + s.getStringAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionByte() { + s.getByteAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionLong() { + s.getLongAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionDouble() { + s.getDoubleAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionFloat() { + s.getFloatAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionBoolean() { + s.getBooleanAt(100); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderFactoryTest.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderFactoryTest.java new file mode 100644 index 000000000..5dc5be8b2 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderFactoryTest.java @@ -0,0 +1,31 @@ +package ru.fizteh.fivt.students.kotsurba.storeable.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.storeable.MyTableProviderFactory; + +import java.io.IOException; + +public class MyTableProviderFactoryTest { + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @Test(expected = IllegalArgumentException.class) + public void testCreateNull() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + factory.create(null); + } + + @Test + public void testCreateNotNull() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + Assert.assertNotNull(factory.create(folder.newFolder("folder").getCanonicalPath())); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateEmpty() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + Assert.assertNotNull(factory.create("")); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java new file mode 100644 index 000000000..37c214152 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java @@ -0,0 +1,69 @@ +package ru.fizteh.fivt.students.kotsurba.storeable.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.storage.structured.TableProvider; +import ru.fizteh.fivt.storage.structured.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.storeable.MyTableProviderFactory; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class MyTableProviderTest { + static TableProviderFactory factory; + static TableProvider provider; + static String path; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void before() throws IOException { + path = folder.newFolder().getCanonicalPath(); + provider = factory.create(path); + Assert.assertNotNull(provider); + } + + @Test(expected = Error.class) + public void testSignature() { + new File(path, "test").mkdirs(); + provider.getTable("test"); + } + + @Test(expected = Error.class) + public void testSignatureEmpty() throws IOException { + File file = new File(path, "test"); + file.mkdirs(); + new File(file, "signature.tsv").createNewFile(); + provider.getTable("test"); + } + + @Test + public void testRemove() throws IOException { + List> types = new ArrayList<>(); + types.add(String.class); + types.add(Integer.class); + + Table table = provider.createTable("simple", types); + Assert.assertNotNull(table); + Assert.assertNotNull(provider.getTable("simple")); + provider.removeTable("simple"); + Assert.assertNull(provider.getTable("simple")); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyTypes() throws IOException { + List> types = new ArrayList<>(); + + Table table = provider.createTable("simple", types); + } + +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java new file mode 100644 index 000000000..9036fdd50 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java @@ -0,0 +1,195 @@ +package ru.fizteh.fivt.students.kotsurba.storeable.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.*; +import ru.fizteh.fivt.students.kotsurba.storeable.MyTableProviderFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +public class MyTableTest { + static Table table; + static TableProviderFactory factory; + static TableProvider provider; + static List> types; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void beforeTest() throws IOException { + provider = factory.create(folder.newFolder("folder").getCanonicalPath()); + types = new ArrayList<>(); + types.add(String.class); + types.add(Integer.class); + + table = provider.createTable("simple", types); + + } + + public void storeableEquals(Storeable a, Storeable b) { + for (int i = 0; i < table.getColumnsCount(); ++i) { + Assert.assertEquals(a.getColumnAt(i), b.getColumnAt(i)); + } + } + + @Test + public void testGetPutSimple() throws IOException { + Storeable storeable = provider.createFor(table); + + storeable.setColumnAt(0, "new_value"); + storeable.setColumnAt(1, 100); + + Storeable old = provider.createFor(table); + old.setColumnAt(0, "new_value"); + old.setColumnAt(1, 100); + + Assert.assertNull(table.put("simple", storeable)); + storeableEquals(table.get("simple"), storeable); + + Assert.assertEquals(table.commit(), 1); + storeable.setColumnAt(0, "very_new"); + storeable.setColumnAt(1, null); + Assert.assertNull(table.put("null", storeable)); + storeableEquals(table.get("null"), storeable); + + storeableEquals(table.remove("null"), storeable); + storeableEquals(table.put("simple", storeable), old); + + Assert.assertEquals(table.rollback(), 1); + + storeableEquals(table.remove("simple"), old); + Assert.assertEquals(table.commit(), 1); + + Assert.assertNull(table.put("key", old)); + Assert.assertEquals(table.commit(), 1); + + storeableEquals(table.put("key", old), old); + Assert.assertEquals(table.commit(), 0); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutNullValue() { + table.put("simple", null); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutSpasedKey() { + Storeable storeable = provider.createFor(table); + + storeable.setColumnAt(0, "n e w_ v a lu e"); + storeable.setColumnAt(1, 100); + + table.put(" ", storeable); + } + + @Test + public void testPutGet() throws IOException { + types = new ArrayList<>(); + types.add(Long.class); + types.add(Long.class); + + Table table = provider.createTable("simple1", types); + + Storeable storeable = provider.createFor(table); + + storeable.setColumnAt(0, (long) 123123123); + storeable.setColumnAt(1, (long) 100); + + Assert.assertNull(table.put("simple", storeable)); + storeableEquals(table.get("simple"), storeable); + } + + @Test(expected = ColumnFormatException.class) + public void testStoreableHasMoreLength() throws IOException { + List> types1 = new ArrayList<>(); + types1.add(Long.class); + types1.add(Boolean.class); + + Table table1 = provider.createTable("super1", types1); + + List> types2 = new ArrayList<>(); + types2.add(Long.class); + types2.add(Boolean.class); + types2.add(Byte.class); + Table table2 = provider.createTable("super2", types2); + + Storeable storeable = provider.createFor(table1); + + storeable.setColumnAt(0, (long) 123123123); + storeable.setColumnAt(1, true); + + Assert.assertNull(table1.put("simple", storeable)); + storeableEquals(table1.get("simple"), storeable); + + storeable = provider.createFor(table2); + + storeable.setColumnAt(0, 1); + storeable.setColumnAt(1, false); + storeable.setColumnAt(2, 1); + + Assert.assertNull(table2.put("simple", storeable)); + storeableEquals(table2.get("simple"), storeable); + + table1.put("sdasd", storeable); + } + + @Test(expected = ColumnFormatException.class) + public void testStoreableHasLessLength() throws IOException { + List> types1 = new ArrayList<>(); + types1.add(Long.class); + types1.add(Boolean.class); + + Table table1 = provider.createTable("super1", types1); + + List> types2 = new ArrayList<>(); + types2.add(Long.class); + types2.add(Boolean.class); + types2.add(Byte.class); + Table table2 = provider.createTable("super2", types2); + + Storeable storeable = provider.createFor(table1); + + storeable.setColumnAt(0, (long) 123123123); + storeable.setColumnAt(1, true); + + Assert.assertNull(table1.put("simple", storeable)); + storeableEquals(table1.get("simple"), storeable); + + Storeable storeable2 = provider.createFor(table2); + + storeable2.setColumnAt(0, 1); + storeable2.setColumnAt(1, false); + storeable2.setColumnAt(2, 1); + + Assert.assertNull(table2.put("simple", storeable2)); + storeableEquals(table2.get("simple"), storeable2); + + table2.put("sdasd", storeable); + } + + @Test + public void testEmptyStringInStoreable() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, ""); + Assert.assertNull(table.put("abacaba", storeable)); + Assert.assertEquals(storeable.getStringAt(0), ""); + } + + @Test + public void testList() { + } + + +} From 34af563f97f7c803cd98ec38e530e54506d53ac9 Mon Sep 17 00:00:00 2001 From: taftafa Date: Thu, 25 Dec 2014 04:44:08 +0400 Subject: [PATCH 09/13] Fixed constant JUnit. --- .../fivt/students/kotsurba/junit/DataBaseTable.java | 10 +++++----- .../students/kotsurba/junit/tests/MyTableTest.java | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java index f2eae3e60..b21bdb6de 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/DataBaseTable.java @@ -11,6 +11,11 @@ public final class DataBaseTable implements TableProvider { private String tableDir; private Map tableInUse; + public DataBaseTable(String newTableDir) { + tableDir = newTableDir; + tableInUse = new HashMap(); + } + public DataBase getTableFromMap(final String name) { if (!tableInUse.containsKey(name)) { tableInUse.put(name, new DataBase(name)); @@ -24,11 +29,6 @@ public void deleteTableFromMap(final String name) { } } - public DataBaseTable(String newTableDir) { - tableDir = newTableDir; - tableInUse = new HashMap(); - } - private void checkName(final String name) { if ((name == null) || name.trim().length() == 0) { throw new IllegalArgumentException("Cannot create table! Wrong name!"); diff --git a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java index 0a54b106a..94ddd868b 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java +++ b/src/ru/fizteh/fivt/students/kotsurba/junit/tests/MyTableTest.java @@ -77,7 +77,7 @@ public void testPutGetRemoveRussian() { @Test public void testSizeCommit() { Assert.assertEquals(table.size(), 0); - int count = (Math.abs(new Random().nextInt()) % 255) + 100; + int count = (Math.abs(1000000) % 255) + 100; for (int i = 0; i < count; ++i) { Assert.assertNull(table.put(Integer.toString(i), "size test")); } @@ -93,7 +93,7 @@ public void testSizeCommit() { @Test public void testRollback() { Assert.assertEquals(table.size(), 0); - int count = (Math.abs(new Random().nextInt()) % 255) + 100; + int count = (Math.abs(3000000) % 255) + 100; for (int i = 0; i < count; ++i) { Assert.assertNull(table.put(Integer.toString(i), "rollback test")); } From 12805800ebc1e075558df6376a0d47a0bab06fae Mon Sep 17 00:00:00 2001 From: taftafa Date: Thu, 25 Dec 2014 04:53:13 +0400 Subject: [PATCH 10/13] Fixed Storeable. --- .../students/kotsurba/storeable/Context.java | 16 +++++- .../students/kotsurba/storeable/DataBase.java | 35 ++++++------ .../kotsurba/storeable/DataBaseException.java | 2 +- .../kotsurba/storeable/DataBaseFile.java | 49 +++++++++-------- .../kotsurba/storeable/DataBaseTable.java | 28 ++++------ .../students/kotsurba/storeable/DbMain.java | 47 +--------------- .../storeable/MyTableProviderFactory.java | 2 +- .../kotsurba/storeable/ShellCreateTable.java | 9 +-- .../kotsurba/storeable/ShellDbCommit.java | 12 +--- .../kotsurba/storeable/ShellDbGet.java | 13 ++--- .../kotsurba/storeable/ShellDbList.java | 12 +--- .../kotsurba/storeable/ShellDbPut.java | 13 ++--- .../kotsurba/storeable/ShellDbRemove.java | 12 +--- .../kotsurba/storeable/ShellDbRollback.java | 12 +--- .../kotsurba/storeable/ShellDbShow.java | 13 +---- .../kotsurba/storeable/ShellDbSize.java | 12 +--- .../kotsurba/storeable/ShellDropTable.java | 14 ++--- .../kotsurba/storeable/ShellExit.java | 10 +--- .../storeable/ShellExitException.java | 2 +- .../kotsurba/storeable/ShellRunner.java | 55 +++++++++++++++++++ .../kotsurba/storeable/ShellUseTable.java | 17 ++---- .../kotsurba/storeable/WorkWithJSON.java | 1 + .../storeable/tests/MyTableProviderTest.java | 4 +- .../kotsurba/storeable/tests/MyTableTest.java | 3 - 24 files changed, 172 insertions(+), 221 deletions(-) create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/ShellRunner.java diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java index c67a4d0ed..ba215d175 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/Context.java @@ -4,14 +4,26 @@ import ru.fizteh.fivt.storage.structured.TableProvider; public class Context { - public TableProvider provider; - public Table table; + private TableProvider provider; + private Table table; public Context(TableProvider newProvider) { provider = newProvider; table = null; } + public TableProvider getProvider() { + return provider; + } + + public Table getTable() { + return table; + } + + public void setTable(Table newTable) { + table = newTable; + } + public int getChanges() { if (table != null) { return ((DataBase) table).getNewKeys(); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java index 65b126ae2..b42e7531d 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBase.java @@ -21,6 +21,9 @@ public final class DataBase implements Table { public static final int DIRECTORY_COUNT = 16; public static final int FILES_COUNT = 16; + public static final String DIRECTORY_FORMAT = "dir"; + public static final String FILES_FORMAT = "dat"; + public static final String SIGNATURE_FILE = "signature.tsv"; public final class DirFile { private int nDir; @@ -38,11 +41,11 @@ public DirFile(final int newDir, final int newFile) { } private String getNDirectory() { - return Integer.toString(nDir) + ".dir"; + return Integer.toString(nDir) + "." + DIRECTORY_FORMAT; } private String getNFile() { - return Integer.toString(nFile) + ".dat"; + return Integer.toString(nFile) + "." + FILES_FORMAT; } public int getId() { @@ -63,14 +66,14 @@ public DataBase(final String dbDirectory, final TableProvider newProvider, final types = MySignature.getSignature(dataBaseDirectory); } - isCorrect(); - files = new DataBaseFile[256]; + checkInternalState(); + files = new DataBaseFile[DIRECTORY_COUNT * FILES_COUNT]; loadFiles(); } private void checkNames(final String[] dirs, final String secondName) { for (int i = 0; i < dirs.length; ++i) { - if (dirs[i].equals("signature.tsv")) { + if (dirs[i].equals(SIGNATURE_FILE)) { continue; } String[] name = dirs[i].split("\\."); @@ -97,7 +100,7 @@ private void isCorrectDirectory(final String dirName) { throw new MultiDataBaseException(dirName + " isn't a directory!"); } String[] dirs = file.list(); - checkNames(dirs, "dat"); + checkNames(dirs, FILES_FORMAT); for (int i = 0; i < dirs.length; ++i) { if (new File(dirName, dirs[i]).isDirectory()) { throw new MultiDataBaseException(dirName + File.separator + dirs[i] + " isn't a file!"); @@ -105,16 +108,16 @@ private void isCorrectDirectory(final String dirName) { } } - private void isCorrect() { + private void checkInternalState() { File file = new File(dataBaseDirectory); if (file.isFile()) { throw new MultiDataBaseException(dataBaseDirectory + " isn't directory!"); } String[] dirs = file.list(); - checkNames(dirs, "dir"); + checkNames(dirs, DIRECTORY_FORMAT); for (int i = 0; i < dirs.length; ++i) { - if (!dirs[i].equals("signature.tsv")) { + if (!dirs[i].equals(SIGNATURE_FILE)) { isCorrectDirectory(dataBaseDirectory + File.separator + dirs[i]); } } @@ -170,9 +173,9 @@ public void drop() { } } } - tryDeleteDirectory(Integer.toString(i) + ".dir"); + tryDeleteDirectory(Integer.toString(i) + "." + DIRECTORY_FORMAT); } - if (!new File(dataBaseDirectory, "signature.tsv").delete()) { + if (!new File(dataBaseDirectory, SIGNATURE_FILE).delete()) { throw new DataBaseException("Cannot delete a file!"); } } @@ -215,7 +218,7 @@ public Storeable remove(final String keyStr) { @Override public int commit() { int allNew = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allNew += files[i].getNewKeys(); files[i].commit(); } @@ -225,7 +228,7 @@ public int commit() { @Override public int size() { int allSize = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allSize += files[i].getSize(); } return allSize; @@ -233,7 +236,7 @@ public int size() { @Override public List list() { - List result = new ArrayList(); + List result = new ArrayList<>(); for (DataBaseFile dbf : files) { if (dbf.getSize() != 0) { List ans = dbf.getAllKeys(); @@ -249,7 +252,7 @@ public List list() { @Override public int rollback() { int allCanceled = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allCanceled += files[i].getNewKeys(); files[i].rollback(); } @@ -268,7 +271,7 @@ public int getColumnsCount() { public int getNewKeys() { int allNewSize = 0; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { allNewSize += files[i].getNewKeys(); } return allNewSize; diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java index a73a6cd0f..7956622e5 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseException.java @@ -1,6 +1,6 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -public class DataBaseException extends Error { +public class DataBaseException extends RuntimeException { public DataBaseException(final String message) { super(message); } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java index 83d3c1aca..d01ffb1b8 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseFile.java @@ -15,14 +15,13 @@ public class DataBaseFile { - static final byte OLD_NODE = 1; - static final byte NEW_NODE = 2; - static final byte MODIFIED_NODE = 3; - static final byte DELETED_NODE = 4; + public enum NodeStatus {OLD_NODE, NEW_NODE, MODIFIED_NODE, DELETED_NODE} + public static final int DIRECTORY_COUNT = 16; + public static final int FILES_COUNT = 16; public final class Node { - private byte status; + private NodeStatus status; private boolean old; private byte[] key; private byte[] value; @@ -33,7 +32,7 @@ public int getZeroByte() { } public Node(final byte[] newKey, final byte[] newValue) { - status = NEW_NODE; + status = NodeStatus.NEW_NODE; key = newKey; value = newValue; oldValue = null; @@ -62,7 +61,7 @@ public Node(final RandomAccessFile inputFile) throws IOException { } public void setOld() { - status = OLD_NODE; + status = NodeStatus.OLD_NODE; old = true; oldValue = value; } @@ -72,15 +71,15 @@ public void setKey(final byte[] newKey) { } public void setValue(final byte[] newValue) { - status = MODIFIED_NODE; + status = NodeStatus.MODIFIED_NODE; if ((oldValue != null) && (Arrays.equals(oldValue, newValue))) { - status = OLD_NODE; + status = NodeStatus.OLD_NODE; } value = newValue; } public void write(final RandomAccessFile outputFile) throws IOException { - if (status == DELETED_NODE) { + if (status == NodeStatus.DELETED_NODE) { return; } outputFile.writeInt(key.length); @@ -89,17 +88,17 @@ public void write(final RandomAccessFile outputFile) throws IOException { outputFile.write(value); } - public byte getStatus() { + public NodeStatus getStatus() { return status; } - public void setStatus(byte newStatus) { + public void setStatus(NodeStatus newStatus) { status = newStatus; } public void remove() { value = null; - status = DELETED_NODE; + status = NodeStatus.DELETED_NODE; } } @@ -130,7 +129,8 @@ public DataBaseFile(final String newFileName, final int newDirectoryNumber, fina public boolean check() throws IOException { for (Node node : data) { - if (!((node.getZeroByte() % 16 == direcotryNumber) && ((node.getZeroByte() / 16) % 16 == fileNumber))) { + if (!((node.getZeroByte() % DIRECTORY_COUNT == direcotryNumber) + && ((node.getZeroByte() / DIRECTORY_COUNT) % FILES_COUNT == fileNumber))) { throw new IOException("Wrong file format key[0] = " + String.valueOf(node.getZeroByte()) + " in file " + fileName); } @@ -237,9 +237,9 @@ public String put(final String keyStr, final String valueStr) { data.add(new Node(key, value)); return null; } else { - int status = data.get(index).status; + NodeStatus status = data.get(index).status; String result = null; - if (status != DELETED_NODE) { + if (status != NodeStatus.DELETED_NODE) { result = new String(data.get(index).value); } data.get(index).setValue(value); @@ -251,7 +251,7 @@ public String get(final String keyStr) { byte[] key = keyStr.getBytes(StandardCharsets.UTF_8); int index = search(key); if (index != -1) { - if (data.get(index).status == DELETED_NODE) { + if (data.get(index).status == NodeStatus.DELETED_NODE) { return null; } return new String(data.get(index).value); @@ -267,7 +267,7 @@ public String remove(final String keyStr) { return null; } else { String result; - if (data.get(index).status == DELETED_NODE) { + if (data.get(index).status == NodeStatus.DELETED_NODE) { result = null; } else { result = new String(data.get(index).value); @@ -280,8 +280,8 @@ public String remove(final String keyStr) { public int getNewKeys() { int result = 0; for (Node node : data) { - if ((node.getStatus() == NEW_NODE) || (node.getStatus() == MODIFIED_NODE) - || ((node.getStatus() == DELETED_NODE) && (node.old))) { + if ((node.getStatus() == NodeStatus.NEW_NODE) || (node.getStatus() == NodeStatus.MODIFIED_NODE) + || ((node.getStatus() == NodeStatus.DELETED_NODE) && (node.old))) { ++result; } } @@ -291,7 +291,7 @@ public int getNewKeys() { public int getSize() { int result = 0; for (Node node : data) { - if (node.getStatus() != DELETED_NODE) { + if (node.getStatus() != NodeStatus.DELETED_NODE) { ++result; } } @@ -300,9 +300,9 @@ public int getSize() { public List getAllKeys() { - List result = new ArrayList(); + List result = new ArrayList(); for (Node node : data) { - if (node.getStatus() != DELETED_NODE) { + if (node.getStatus() != NodeStatus.DELETED_NODE) { result.add(new String(node.key)); } } @@ -312,7 +312,7 @@ public List getAllKeys() { public void commit() { save(); for (int i = 0; i < data.size(); ) { - if (data.get(i).getStatus() == DELETED_NODE) { + if (data.get(i).getStatus() == NodeStatus.DELETED_NODE) { data.remove(i); } else { data.get(i).setOld(); @@ -325,4 +325,5 @@ public void rollback() { data.clear(); load(); } + } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java index 72d05dd09..70a0f9fa7 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DataBaseTable.java @@ -3,10 +3,7 @@ import java.io.File; import java.io.IOException; import java.text.ParseException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.json.JSONArray; import org.json.JSONException; @@ -38,13 +35,12 @@ private void checkName(final String name) { @Override public Table createTable(final String tableName, List> columnTypes) throws IOException { checkName(tableName); - String fullPath = tableDir + File.separator + tableName; if (columnTypes == null || columnTypes.size() == 0) { throw new IllegalArgumentException("wrong type (null)"); } - File file = new File(fullPath); + File file = new File(tableDir, tableName); if (file.exists()) { return null; @@ -54,7 +50,7 @@ public Table createTable(final String tableName, List> columnTypes) thr throw new MultiDataBaseException("Cannot create table " + tableName); } - DataBase table = new DataBase(fullPath, this, columnTypes); + DataBase table = new DataBase(file.toString(), this, columnTypes); tableInUse.put(tableName, table); return table; } @@ -62,9 +58,9 @@ public Table createTable(final String tableName, List> columnTypes) thr @Override public void removeTable(final String tableName) throws IOException { checkName(tableName); - String fullPath = tableDir + File.separator + tableName; - File file = new File(fullPath); + File file = new File(tableDir, tableName); + if (!file.exists()) { throw new IllegalStateException("Table not exist already!"); } @@ -84,9 +80,9 @@ public void removeTable(final String tableName) throws IOException { @Override public Table getTable(String tableName) { checkName(tableName); - String fullPath = tableDir + File.separator + tableName; - File file = new File(fullPath); + File file = new File(tableDir, tableName); + if ((!file.exists()) || (file.isFile())) { return null; } @@ -94,7 +90,7 @@ public Table getTable(String tableName) { return tableInUse.get(tableName); } else { try { - DataBase table = new DataBase(fullPath, this, null); + DataBase table = new DataBase(file.toString(), this, null); tableInUse.put(tableName, table); return table; } catch (IOException e) { @@ -105,7 +101,7 @@ public Table getTable(String tableName) { @Override public Storeable deserialize(Table table, String value) throws ParseException { - JSONArray json = null; + JSONArray json; try { json = new JSONArray(value); } catch (JSONException e) { @@ -149,10 +145,8 @@ public Storeable createFor(Table table, List values) throws ColumnFormatExcep @Override public List getTableNames() { - List result = new ArrayList(); - for (String str : new File(tableDir).list()) { - result.add(str); - } + List result = new ArrayList(); + Collections.addAll(result, new File(tableDir).list()); return result; } } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java index cb9539cfc..fbba30947 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/DbMain.java @@ -1,13 +1,9 @@ package ru.fizteh.fivt.students.kotsurba.storeable; import java.io.IOException; -import java.util.Scanner; import ru.fizteh.fivt.storage.structured.TableProviderFactory; import ru.fizteh.fivt.students.kotsurba.filemap.shell.Shell; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandParser; -import ru.fizteh.fivt.students.kotsurba.shell.ShellMain; public class DbMain { private static Shell shell; @@ -46,54 +42,15 @@ private static void initShell() { } } - private static void packetRun(final String[] args) { - try { - CommandParser parser = new CommandParser(args); - while (!parser.isEmpty()) { - shell.executeCommand(parser.getCommand()); - } - } catch (InvalidCommandException | MultiDataBaseException | DataBaseWrongFileFormat | RuntimeException e) { - System.err.println(e.getMessage()); - } - } - - private static void interactiveRun() { - Scanner scanner = new Scanner(System.in); - System.out.print(" $ "); - while (true) { - try { - if (!scanner.hasNextLine()) { - throw new ShellExitException("Ctrl + D exit!"); - } - - String command = scanner.nextLine(); - - if (ShellMain.hasTerminalSymbol(command)) { - throw new ShellExitException("Ctrl + D exit or EOF!"); - } - - CommandParser parser = new CommandParser(command); - if (!parser.isEmpty()) { - shell.executeCommand(parser.getCommand()); - } - } catch (MultiDataBaseException | DataBaseWrongFileFormat | InvalidCommandException - | RuntimeException e) { - System.err.println(e.getMessage()); - } finally { - System.out.print(" $ "); - } - } - } - public static void main(final String[] args) { try { checkDbDir(); initShell(); if (args.length > 0) { - packetRun(args); + ShellRunner.packetRun(shell, args); } else { - interactiveRun(); + ShellRunner.interactiveRun(shell); } } catch (DataBaseException e) { diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java index 8b2857f19..52740da25 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/MyTableProviderFactory.java @@ -23,7 +23,7 @@ public TableProvider create(String dir) throws IOException { } if (!tableDirFile.isDirectory()) { - throw new IllegalArgumentException("Wrong dir " + dir); + throw new IllegalArgumentException("Wrong directory " + dir); } return new DataBaseTable(dir); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java index 1ddd96f10..13bf88abc 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellCreateTable.java @@ -2,23 +2,18 @@ import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandString; import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; import java.io.IOException; public class ShellCreateTable extends SimpleShellCommand { - private Context context; public ShellCreateTable(Context newContext) { - context = newContext; - setName("create"); - setNumberOfArgs(3); - setHint("usage: create
()"); + super("create", 3, "usage: create
()", newContext); } public void run() { try { - if (context.provider.createTable(getArg(1), MySignature.getTypes(getSpacedArg(2))) != null) { + if (context.getProvider().createTable(getArg(1), MySignature.getTypes(getSpacedArg(2))) != null) { System.out.println("created"); } else { System.out.println(getArg(1) + " exists"); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java index 925258ea3..13ab8fc6c 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbCommit.java @@ -1,24 +1,18 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - import java.io.IOException; public class ShellDbCommit extends SimpleShellCommand { - private Context context; public ShellDbCommit(final Context newContext) { - context = newContext; - setName("commit"); - setNumberOfArgs(1); - setHint("usage: commit"); + super("commit", 1, "usage: commit", newContext); } @Override public void run() { try { - if (context.table != null) { - System.out.println(context.table.commit()); + if (context.getTable() != null) { + System.out.println(context.getTable().commit()); } else { System.out.println("no table"); } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java index 0f2c0ceb8..980567db4 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbGet.java @@ -1,30 +1,25 @@ package ru.fizteh.fivt.students.kotsurba.storeable; import ru.fizteh.fivt.storage.structured.Storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; public class ShellDbGet extends SimpleShellCommand { - private Context context; public ShellDbGet(final Context newContext) { - context = newContext; - setName("get"); - setNumberOfArgs(2); - setHint("usage: get "); + super("get", 2, "usage: get ", newContext); } @Override public void run() { - if (context.table == null) { + if (context.getTable() == null) { System.out.println("no table"); return; } - Storeable storeable = context.table.get(getArg(1)); + Storeable storeable = context.getTable().get(getArg(1)); if (storeable == null) { System.out.println("not found"); } else { System.out.println("found"); - System.out.println(context.provider.serialize(context.table, storeable)); + System.out.println(context.getProvider().serialize(context.getTable(), storeable)); } } } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java index c4b56e8ff..b6999d555 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbList.java @@ -1,26 +1,20 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - import java.util.List; public final class ShellDbList extends SimpleShellCommand { - private Context context; public ShellDbList(final Context newContext) { - context = newContext; - setName("list"); - setNumberOfArgs(1); - setHint("usage: list"); + super("list", 1, "usage: list", newContext); } @Override public void run() { - if (context.table == null) { + if (context.getTable() == null) { System.out.println("no table"); return; } - List str = context.table.list(); + List str = context.getTable().list(); StringBuilder keys = new StringBuilder(); for (String string : str) { keys.append(string).append(", "); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java index a69c6f55e..2a1a84280 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbPut.java @@ -3,33 +3,28 @@ import ru.fizteh.fivt.storage.structured.Storeable; import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandString; import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; import java.text.ParseException; public final class ShellDbPut extends SimpleShellCommand { - private Context context; public ShellDbPut(final Context newContext) { - context = newContext; - setName("put"); - setNumberOfArgs(3); - setHint("usage: put "); + super("put", 3, "usage: put ", newContext); } @Override public void run() { - if (context.table == null) { + if (context.getTable() == null) { System.out.println("no table"); return; } try { - Storeable storeable = ((DataBase) context.table).putStoreable(getArg(1), getSpacedArg(2)); + Storeable storeable = ((DataBase) context.getTable()).putStoreable(getArg(1), getSpacedArg(2)); if (storeable == null) { System.out.println("new"); } else { System.out.println("overwrite"); - System.out.println(context.provider.serialize(context.table, storeable)); + System.out.println(context.getProvider().serialize(context.getTable(), storeable)); } } catch (ParseException e) { System.out.println("wrong type (" + e.getMessage() + ")"); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java index e868a685a..220fee1fb 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRemove.java @@ -1,24 +1,18 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - public final class ShellDbRemove extends SimpleShellCommand { - private Context context; public ShellDbRemove(Context newContext) { - context = newContext; - setName("remove"); - setNumberOfArgs(2); - setHint("usage: remove "); + super("remove", 2, "usage: remove ", newContext); } @Override public void run() { - if (context.table == null) { + if (context.getTable() == null) { System.out.println("no table"); return; } - if (context.table.remove(getArg(1)) == null) { + if (context.getTable().remove(getArg(1)) == null) { System.out.println("not found"); } else { System.out.println("removed"); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java index 0cf56b3d0..8a7688421 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbRollback.java @@ -1,21 +1,15 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - public class ShellDbRollback extends SimpleShellCommand { - private Context context; public ShellDbRollback(final Context newContext) { - context = newContext; - setName("rollback"); - setNumberOfArgs(1); - setHint("usage: rollback"); + super("rollback", 1, "usage: rollback", newContext); } @Override public void run() { - if (context.table != null) { - System.out.println(context.table.rollback()); + if (context.getTable() != null) { + System.out.println(context.getTable().rollback()); } else { System.out.println("no table"); } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java index d51c9a213..383167520 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbShow.java @@ -1,25 +1,18 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - -import java.io.File; import java.util.List; public class ShellDbShow extends SimpleShellCommand { - private Context context; public ShellDbShow(Context newContext) { - context = newContext; - setName("show"); - setNumberOfArgs(2); - setHint("usage: show tables"); + super("show", 2, "usage: show tables", newContext); } public void run() { if (getArg(1).equals("tables")) { - List names = context.provider.getTableNames(); + List names = context.getProvider().getTableNames(); for (String name : names) { - System.out.println(name + " " + context.provider.getTable(name).size()); + System.out.println(name + " " + context.getProvider().getTable(name).size()); } } else { System.out.println("Invalid command!"); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java index 91b81c0cc..73f3f0e84 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDbSize.java @@ -1,21 +1,15 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - public class ShellDbSize extends SimpleShellCommand { - private Context context; public ShellDbSize(final Context newContext) { - context = newContext; - setName("size"); - setNumberOfArgs(1); - setHint("usage: size"); + super("size", 1, "usage: size", newContext); } @Override public void run() { - if (context.table != null) { - System.out.println(context.table.size()); + if (context.getClass() != null) { + System.out.println(context.getTable().size()); } else { System.out.println("no table"); } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java index 466fe343e..958bb235e 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellDropTable.java @@ -1,26 +1,20 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - import java.io.IOException; public class ShellDropTable extends SimpleShellCommand { - private Context context; public ShellDropTable(Context newContext) { - context = newContext; - setName("drop"); - setNumberOfArgs(2); - setHint("usage: drop
"); + super("drop", 2, "usage: drop
", newContext); } public void run() { try { - if ((context.table != null) && (context.table.getName().equals(getArg(1)))) { - context.table = null; + if ((context.getTable() != null) && (context.getTable().getName().equals(getArg(1)))) { + context.setTable(null); } - context.provider.removeTable(getArg(1)); + context.getProvider().removeTable(getArg(1)); System.out.println("dropped"); } catch (IllegalStateException e) { System.out.println(getArg(1) + " not exists"); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java index 70c0d551d..07c534998 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExit.java @@ -1,15 +1,9 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; - public final class ShellExit extends SimpleShellCommand { - private Context context; public ShellExit(final Context newContext) { - context = newContext; - setName("exit"); - setNumberOfArgs(1); - setHint("usage: exit"); + super("exit", 1, "usage: exit", newContext); } @Override @@ -18,7 +12,7 @@ public void run() { throw new ShellExitException("Exit command"); } else { System.out.println(context.getChanges() + " unsaved changes"); - System.out.println("Cant't exit"); + System.out.println("Can't exit"); } } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java index dd1f97c6c..1f839855f 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellExitException.java @@ -1,6 +1,6 @@ package ru.fizteh.fivt.students.kotsurba.storeable; -public class ShellExitException extends Error { +public class ShellExitException extends RuntimeException { public ShellExitException(final String message) { super(message); } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellRunner.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellRunner.java new file mode 100644 index 000000000..00a1c777f --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellRunner.java @@ -0,0 +1,55 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandParser; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; +import ru.fizteh.fivt.students.kotsurba.shell.ShellMain; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.Shell; + +import java.util.Scanner; + +public class ShellRunner { + + public static final String PROMPT = " $ "; + + public static void packetRun(Shell shell, final String[] args) { + try { + CommandParser parser = new CommandParser(args); + while (!parser.isEmpty()) { + shell.executeCommand(parser.getCommand()); + } + } catch (InvalidCommandException | MultiDataBaseException | DataBaseWrongFileFormat | RuntimeException e) { + System.err.println(e.getMessage()); + } + } + + public static void interactiveRun(Shell shell) { + Scanner scanner = new Scanner(System.in); + System.out.print(PROMPT); + while (true) { + try { + if (!scanner.hasNextLine()) { + throw new ShellExitException("Ctrl + D exit!"); + } + + String command = scanner.nextLine(); + + if (ShellMain.hasTerminalSymbol(command)) { + throw new ShellExitException("Ctrl + D exit or EOF!"); + } + + CommandParser parser = new CommandParser(command); + if (!parser.isEmpty()) { + shell.executeCommand(parser.getCommand()); + } + } catch (ShellExitException e) { + throw new ShellExitException(e.getMessage()); + } catch (DataBaseException e) { + throw new DataBaseException(e.getMessage()); + } catch (MultiDataBaseException | DataBaseWrongFileFormat | InvalidCommandException | RuntimeException e) { + System.err.println(e.getMessage()); + } finally { + System.out.print(PROMPT); + } + } + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java index df967ff73..dad568cb2 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/ShellUseTable.java @@ -1,30 +1,25 @@ package ru.fizteh.fivt.students.kotsurba.storeable; import ru.fizteh.fivt.storage.structured.Table; -import ru.fizteh.fivt.students.kotsurba.filemap.shell.SimpleShellCommand; public class ShellUseTable extends SimpleShellCommand { - private Context context; public ShellUseTable(Context newContext) { - context = newContext; - setName("use"); - setNumberOfArgs(2); - setHint("usage: use
"); + super("use", 2, "usage: use
", newContext); } public void run() { - if ((context.table != null) && (context.getChanges() != 0)) { + if ((context.getTable() != null) && (context.getChanges() != 0)) { System.out.println(context.getChanges() + " unsaved changes"); return; } - Table old = context.table; - context.table = context.provider.getTable(getArg(1)); - if (context.table != null) { + Table old = context.getTable(); + context.setTable(context.getProvider().getTable(getArg(1))); + if (context.getTable() != null) { System.out.println("using " + getArg(1)); } else { - context.table = old; + context.setTable(old); System.out.println(getArg(1) + " not exists"); } } diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java index 634da5aa4..c2b441329 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/WorkWithJSON.java @@ -14,6 +14,7 @@ public static String serialize(Table table, Storeable value) throws ColumnFormat value.getColumnAt(table.getColumnsCount()); throw new ColumnFormatException("Too many columns!"); } catch (IndexOutOfBoundsException e) { + //silent } JSONArray array = new JSONArray(); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java index 37c214152..8b6a264e3 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableProviderTest.java @@ -32,13 +32,13 @@ public void before() throws IOException { Assert.assertNotNull(provider); } - @Test(expected = Error.class) + @Test(expected = RuntimeException.class) public void testSignature() { new File(path, "test").mkdirs(); provider.getTable("test"); } - @Test(expected = Error.class) + @Test(expected = RuntimeException.class) public void testSignatureEmpty() throws IOException { File file = new File(path, "test"); file.mkdirs(); diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java index 9036fdd50..ff3d33db2 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/tests/MyTableTest.java @@ -7,10 +7,7 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; - public class MyTableTest { static Table table; From b996c0caccc198a6584f172f8d377b82f20fe7e7 Mon Sep 17 00:00:00 2001 From: taftafa Date: Thu, 25 Dec 2014 05:04:17 +0400 Subject: [PATCH 11/13] Commit tests for JUnit. --- .../storeable/SimpleShellCommand.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/ru/fizteh/fivt/students/kotsurba/storeable/SimpleShellCommand.java diff --git a/src/ru/fizteh/fivt/students/kotsurba/storeable/SimpleShellCommand.java b/src/ru/fizteh/fivt/students/kotsurba/storeable/SimpleShellCommand.java new file mode 100644 index 000000000..3a964e30c --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/storeable/SimpleShellCommand.java @@ -0,0 +1,71 @@ +package ru.fizteh.fivt.students.kotsurba.storeable; + +import ru.fizteh.fivt.students.kotsurba.filemap.shell.CommandString; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.InvalidCommandException; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.ShellCommand; + +public abstract class SimpleShellCommand implements ShellCommand { + protected String name; + protected int numberOfArgs; + protected CommandString args; + protected String hint; + protected Context context; + + public SimpleShellCommand(String newName, int newNumberOfArgs, String newHint, Context newContext) { + name = newName; + numberOfArgs = newNumberOfArgs; + hint = newHint; + context = newContext; + } + + @Override + public void run() { + } + + @Override + public boolean isMyCommand(final CommandString command) { + if (name.equals(command.getArg(0))) { + if (command.length() > numberOfArgs) { + throw new InvalidCommandException(name + ": too many arguments"); + } + if (command.length() < numberOfArgs) { + throw new InvalidCommandException(name + " " + hint); + } + args = command; + return true; + } + return false; + } + + public final String getHint() { + return hint; + } + + public final void setHint(String newHint) { + hint = newHint; + } + + public final String getName() { + return name; + } + + public final int getNumberOfArgs() { + return numberOfArgs; + } + + public void setName(final String newName) { + name = newName; + } + + public void setNumberOfArgs(final int newNumberOfArgs) { + numberOfArgs = newNumberOfArgs; + } + + public String getArg(final int index) { + return args.getArg(index); + } + + public String getSpacedArg(final int index) { + return args.getSpacedArg(index); + } +} From fba1ec153561ee39a0278b6fb7e31c464f0376ca Mon Sep 17 00:00:00 2001 From: taftafa Date: Thu, 25 Dec 2014 05:08:15 +0400 Subject: [PATCH 12/13] This is parallel. --- .../students/kotsurba/parallel/DataBase.java | 307 +++++++++++++++ .../kotsurba/parallel/DataBaseException.java | 7 + .../kotsurba/parallel/DataBaseFile.java | 361 ++++++++++++++++++ .../kotsurba/parallel/DataBaseTable.java | 179 +++++++++ .../parallel/DataBaseWrongFileFormat.java | 7 + .../students/kotsurba/parallel/DbMain.java | 67 ++++ .../parallel/MultiDataBaseException.java | 8 + .../kotsurba/parallel/MySignature.java | 106 +++++ .../kotsurba/parallel/MyStoreable.java | 231 +++++++++++ .../parallel/MyTableProviderFactory.java | 31 ++ .../kotsurba/parallel/ShellExitException.java | 7 + .../kotsurba/parallel/WorkWithJSON.java | 55 +++ .../parallel/tests/MyParallelTest.java | 172 +++++++++ .../parallel/tests/MyStoreableTest.java | 172 +++++++++ .../tests/MyTableProviderFactoryTest.java | 31 ++ .../parallel/tests/MyTableProviderTest.java | 69 ++++ .../kotsurba/parallel/tests/MyTableTest.java | 207 ++++++++++ 17 files changed, 2017 insertions(+) create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/DataBase.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseWrongFileFormat.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/DbMain.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/MultiDataBaseException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/MySignature.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/MyStoreable.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/MyTableProviderFactory.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/ShellExitException.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/WorkWithJSON.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyParallelTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyStoreableTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderFactoryTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderTest.java create mode 100644 src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableTest.java diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBase.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBase.java new file mode 100644 index 000000000..07d63f4c4 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBase.java @@ -0,0 +1,307 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.storage.structured.TableProvider; + + +public final class DataBase implements Table { + + private String name; + private String dataBaseDirectory; + private DataBaseFile[] files; + private TableProvider provider; + private List> types; + + public static final int DIRECTORY_COUNT = 16; + public static final int FILES_COUNT = 16; + public static final String DIRECTORY_FORMAT = "dir"; + public static final String FILES_FORMAT = "dat"; + public static final String SIGNATURE_FILE = "signature.tsv"; + + private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); + public Lock readLock = readWriteLock.readLock(); + public Lock writeLock = readWriteLock.writeLock(); + + public final class DirFile { + private int nDir; + private int nFile; + + public DirFile(int key) { + key = Math.abs(key); + nDir = key % DIRECTORY_COUNT; + nFile = (key / DIRECTORY_COUNT) % FILES_COUNT; + } + + public DirFile(final int newDir, final int newFile) { + nDir = newDir; + nFile = newFile; + } + + private String getNDirectory() { + return Integer.toString(nDir) + "." + DIRECTORY_FORMAT; + } + + private String getNFile() { + return Integer.toString(nFile) + "." + FILES_FORMAT; + } + + public int getId() { + return nDir * DIRECTORY_COUNT + nFile; + } + } + + public DataBase(final String dbDirectory, final TableProvider newProvider, final List> newTypes) + throws IOException { + name = new File(dbDirectory).getName(); + dataBaseDirectory = dbDirectory; + provider = newProvider; + + if (newTypes != null) { + types = newTypes; + MySignature.setSignature(dataBaseDirectory, types); + } else { + types = MySignature.getSignature(dataBaseDirectory); + } + + checkInternalState(); + files = new DataBaseFile[DIRECTORY_COUNT * FILES_COUNT]; + loadFiles(); + } + + private void checkNames(final String[] dirs, final String secondName) { + for (int i = 0; i < dirs.length; ++i) { + if (dirs[i].equals(SIGNATURE_FILE)) { + continue; + } + String[] name = dirs[i].split("\\."); + if (name.length != 2 || !name[1].equals(secondName)) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file in path " + dirs[i]); + } + + int firstName; + try { + firstName = Integer.parseInt(name[0]); + } catch (NumberFormatException e) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dirs[i]); + } + + if ((firstName < 0) || firstName > DIRECTORY_COUNT - 1) { + throw new MultiDataBaseException(dataBaseDirectory + " wrong file first name " + dirs[i]); + } + } + } + + private void isCorrectDirectory(final String dirName) { + File file = new File(dirName); + if (file.isFile()) { + throw new MultiDataBaseException(dirName + " isn't a directory!"); + } + String[] dirs = file.list(); + checkNames(dirs, FILES_FORMAT); + for (int i = 0; i < dirs.length; ++i) { + if (new File(dirName, dirs[i]).isDirectory()) { + throw new MultiDataBaseException(dirName + File.separator + dirs[i] + " isn't a file!"); + } + } + } + + private void checkInternalState() { + File file = new File(dataBaseDirectory); + if (file.isFile()) { + throw new MultiDataBaseException(dataBaseDirectory + " isn't directory!"); + } + + String[] dirs = file.list(); + checkNames(dirs, DIRECTORY_FORMAT); + for (int i = 0; i < dirs.length; ++i) { + if (!dirs[i].equals(SIGNATURE_FILE)) { + isCorrectDirectory(dataBaseDirectory + File.separator + dirs[i]); + } + } + } + + private void tryDeleteDirectory(final String name) { + File file = new File(dataBaseDirectory + File.separator + name); + if (file.exists()) { + if (file.list().length == 0) { + if (!file.delete()) { + throw new DataBaseException("Cannot delete a directory!"); + } + } + } + } + + private String getFullName(final DirFile node) { + return dataBaseDirectory + File.separator + node.getNDirectory() + File.separator + node.getNFile(); + } + + public void loadFiles() throws IOException { + for (int i = 0; i < DIRECTORY_COUNT; ++i) { + for (int j = 0; j < FILES_COUNT; ++j) { + DirFile node = new DirFile(i, j); + DataBaseFile file = new DataBaseFile(getFullName(node), node.nDir, node.nFile, this, provider); + files[node.getId()] = file; + } + } + } + + boolean containsWhitespace(String s) { + for (int i = 0; i < s.length(); ++i) { + if (Character.isWhitespace(s.charAt(i))) { + return true; + } + } + return false; + } + + private void checkKey(final String key) { + if ((key == null) || (key.trim().length() == 0) || (containsWhitespace(key))) { + throw new IllegalArgumentException("Wrong key!"); + } + } + + public void drop() { + for (byte i = 0; i < DIRECTORY_COUNT; ++i) { + for (byte j = 0; j < FILES_COUNT; ++j) { + File file = new File(getFullName(new DirFile(i, j))); + if (file.exists()) { + if (!file.delete()) { + throw new DataBaseException("Cannot delete a file!"); + } + } + } + tryDeleteDirectory(Integer.toString(i) + "." + DIRECTORY_FORMAT); + } + if (!new File(dataBaseDirectory, SIGNATURE_FILE).delete()) { + throw new DataBaseException("Cannot delete a file!"); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public Storeable put(final String keyStr, final Storeable storeableValue) { + checkKey(keyStr); + if (storeableValue == null) { + throw new IllegalArgumentException("Wrong put value = null!"); + } + DirFile node = new DirFile(keyStr.getBytes()[0]); + DataBaseFile file = files[node.getId()]; + String value = WorkWithJSON.serialize(this, storeableValue); + + String result; + result = file.put(keyStr, value); + return WorkWithJSON.deserialize(this, result); + } + + @Override + public Storeable get(final String keyStr) { + checkKey(keyStr); + DirFile node = new DirFile(keyStr.getBytes()[0]); + + String result; + result = files[node.getId()].get(keyStr); + return WorkWithJSON.deserialize(this, result); + } + + @Override + public Storeable remove(final String keyStr) { + checkKey(keyStr); + DirFile node = new DirFile(keyStr.getBytes()[0]); + DataBaseFile file = files[node.getId()]; + + String result; + result = files[node.getId()].remove(keyStr); + return WorkWithJSON.deserialize(this, result); + } + + @Override + public int commit() { + int allNew = 0; + writeLock.lock(); + try { + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { + allNew += files[i].getNewKeys(); + files[i].commit(); + } + } finally { + writeLock.unlock(); + } + return allNew; + } + + @Override + public int size() { + int allSize = 0; + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { + allSize += files[i].getSize(); + } + return allSize; + } + + @Override + public List list() { + List result = new ArrayList<>(); + for (DataBaseFile dbf : files) { + if (dbf.getSize() != 0) { + List ans = dbf.getAllKeys(); + for (String x : ans) { + result.add(x); + } + } + } + return result; + } + + @Override + public int rollback() { + int allCanceled = 0; + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { + allCanceled += files[i].getNewKeys(); + files[i].rollback(); + } + return allCanceled; + } + + @Override + public int getNumberOfUncommittedChanges() { + return getNewKeys(); + } + + @Override + public int getColumnsCount() { + return types.size(); + } + + public int getNewKeys() { + int allNewSize = 0; + for (int i = 0; i < DIRECTORY_COUNT * FILES_COUNT; ++i) { + allNewSize += files[i].getNewKeys(); + } + return allNewSize; + } + + @Override + public Class getColumnType(int columnIndex) throws IndexOutOfBoundsException { + if ((columnIndex < 0) || (columnIndex >= types.size())) { + throw new IndexOutOfBoundsException("getColumnType: columnIndex is wrong"); + } + return types.get(columnIndex); + } + + public Storeable putStoreable(String keyStr, String valueStr) throws ParseException { + return put(keyStr, provider.deserialize(this, valueStr)); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseException.java new file mode 100644 index 000000000..e4448fa47 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseException.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +public class DataBaseException extends RuntimeException { + public DataBaseException(final String message) { + super(message); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java new file mode 100644 index 000000000..bf9d6703e --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java @@ -0,0 +1,361 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + + +import ru.fizteh.fivt.storage.structured.TableProvider; + +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.*; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class DataBaseFile { + + protected final String fileName; + protected File file; + private File dir; + private int fileNumber; + private int direcotryNumber; + private DataBase table; + private TableProvider provider; + + public static final int DIRECTORY_COUNT = 16; + public static final int FILES_COUNT = 16; + + private ThreadLocal> diff = new ThreadLocal>() { + @Override + public HashMap initialValue() { + return new HashMap(); + } + }; + + private ThreadLocal> deleted = new ThreadLocal>() { + @Override + public HashSet initialValue() { + return new HashSet(); + } + }; + + private Lock readLock; + private Lock writeLock; + + private Map old; + + public DataBaseFile(final String newFileName, final int newDirectoryNumber, final int newFileNumber, + DataBase newTable, TableProvider newProvider) throws IOException { + fileName = newFileName; + + table = newTable; + provider = newProvider; + + readLock = table.readLock; + writeLock = table.writeLock; + + fileNumber = newFileNumber; + direcotryNumber = newDirectoryNumber; + + file = new File(fileName); + dir = new File(file.getParent()); + + old = new HashMap<>(); + + load(); + check(); + } + + public boolean check() throws IOException { + for (Map.Entry node : old.entrySet()) { + int zeroByte = Math.abs(node.getKey().getBytes(StandardCharsets.UTF_8)[0]); + if (!((zeroByte % DIRECTORY_COUNT == direcotryNumber) + && ((zeroByte / DIRECTORY_COUNT) % FILES_COUNT == fileNumber))) { + throw new IOException("Wrong file format key[0] = " + String.valueOf(zeroByte) + + " in file " + fileName); + } + try { + provider.deserialize(table, node.getValue()); + } catch (ParseException e) { + throw new IOException("Invalid file format! (parse exception error!)"); + } + } + return true; + } + + private void load() { + try { + if (dir.exists() && dir.list().length == 0) { + throw new IOException("Empty dir!"); + } + if (!dir.exists() || !file.exists()) { + return; + } + try (RandomAccessFile inputFile = new RandomAccessFile(fileName, "rw")) { + while (inputFile.getFilePointer() < inputFile.length() - 1) { + + int keyLength = inputFile.readInt(); + int valueLength = inputFile.readInt(); + + if ((keyLength <= 0) || (valueLength <= 0)) { + throw new DataBaseWrongFileFormat("Wrong file format! " + file.getName()); + } + + byte[] key; + byte[] value; + + try { + key = new byte[keyLength]; + value = new byte[valueLength]; + } catch (OutOfMemoryError e) { + throw new DataBaseWrongFileFormat("Some key or value are too large in " + file.getName()); + } + + inputFile.read(key); + inputFile.read(value); + + old.put(new String(key, StandardCharsets.UTF_8), new String(value, StandardCharsets.UTF_8)); + } + } + if (old.size() == 0) { + throw new IOException("Empty file!"); + } + } catch (FileNotFoundException e) { + throw new DataBaseException("File not found!"); + } catch (IOException e) { + throw new DataBaseException("File load error!"); + } + } + + public void createPath() { + if (dir.exists()) { + return; + } + + if (!dir.mkdir()) { + throw new DataBaseException("Cannot create directory!"); + } + } + + public void deletePath() { + if (!dir.exists()) { + return; + } + + if (dir.list().length != 0) { + return; + } + + if (!dir.delete()) { + throw new DataBaseException("Cannot delete a directory!"); + } + } + + public void save() { + try { + if (getSize() == 0) { + if ((file.exists()) && (!file.delete())) { + throw new DataBaseException("Cannot delete a file!"); + } + deletePath(); + } else { + createPath(); + if (!file.exists()) { + if (!file.createNewFile()) { + throw new DataBaseException("Cannot create a file " + fileName); + } + } + try (RandomAccessFile outputFile = new RandomAccessFile(fileName, "rw")) { + for (Map.Entry node : old.entrySet()) { + outputFile.writeInt(node.getKey().getBytes(StandardCharsets.UTF_8).length); + outputFile.writeInt(node.getValue().getBytes(StandardCharsets.UTF_8).length); + outputFile.write(node.getKey().getBytes(StandardCharsets.UTF_8)); + outputFile.write(node.getValue().getBytes(StandardCharsets.UTF_8)); + } + outputFile.setLength(outputFile.getFilePointer()); + } + } + } catch (FileNotFoundException e) { + throw new DataBaseException("File save error!"); + } catch (IOException e) { + throw new DataBaseException("Write to file error!"); + } + } + + public String put(final String key, final String value) { + String result = null; + + if (diff.get().containsKey(key)) { + result = diff.get().get(key); + } else { + readLock.lock(); + try { + if (old.containsKey(key)) { + result = old.get(key); + } + } finally { + readLock.unlock(); + } + } + + if (deleted.get().contains(key)) { + deleted.get().remove(key); + result = null; + } + + diff.get().put(key, value); + + return result; + } + + public String get(final String key) { + if (deleted.get().contains(key)) { + return null; + } + + if (diff.get().containsKey(key)) { + return diff.get().get(key); + } + + readLock.lock(); + try { + if (old.containsKey(key)) { + return old.get(key); + } + } finally { + readLock.unlock(); + } + + return null; + } + + public String remove(final String key) { + if (deleted.get().contains(key)) { + return null; + } + + String result = null; + + if (diff.get().containsKey(key)) { + result = diff.get().get(key); + diff.get().remove(key); + deleted.get().add(key); + return result; + } + + readLock.lock(); + try { + if (old.containsKey(key)) { + result = old.get(key); + deleted.get().add(key); + } + } finally { + readLock.unlock(); + } + + return result; + } + + private void normalize() { + Set newDeleted = new HashSet<>(); + newDeleted.addAll(deleted.get()); + + for (String key : old.keySet()) { + if (old.get(key).equals(diff.get().get(key))) { + diff.get().remove(key); + } + if (newDeleted.contains(key)) { + newDeleted.remove(key); + } + } + + for (String key : deleted.get()) { + if (diff.get().containsKey(key)) { + diff.get().remove(key); + } + } + + for (String key : newDeleted) { + deleted.get().remove(key); + } + } + + List getAllKeys() { + List result = new ArrayList(); + Set newDeleted = new HashSet<>(); + newDeleted.addAll(deleted.get()); + readLock.lock(); + try { + normalize(); + + for (String key : old.keySet()) { + if (!deleted.get().contains(key)) { + result.add(key); + } + } + + for (String key : diff.get().keySet()) { + if (!(deleted.get().contains(key) || old.containsKey(key))) { + result.add(key); + } + } + return result; + } finally { + readLock.unlock(); + } + } + + public int getNewKeys() { + readLock.lock(); + try { + normalize(); + return diff.get().size() + deleted.get().size(); + } finally { + readLock.unlock(); + } + } + + public int getSize() { + readLock.lock(); + try { + normalize(); + int result = diff.get().size() + old.size() - deleted.get().size(); + for (String key : diff.get().keySet()) { + if (old.containsKey(key)) { + --result; + } + } + return result; + } finally { + readLock.unlock(); + } + } + + public void commit() { + normalize(); + + if (diff.get().size() == 0 && deleted.get().size() == 0) { + return; + } + + for (Map.Entry node : diff.get().entrySet()) { + old.put(node.getKey(), node.getValue()); + } + + for (String key : deleted.get()) { + old.remove(key); + } + + + diff.get().clear(); + deleted.get().clear(); + + save(); + } + + public void rollback() { + diff.get().clear(); + deleted.get().clear(); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java new file mode 100644 index 000000000..cbbc91b09 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java @@ -0,0 +1,179 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.json.JSONArray; +import org.json.JSONException; +import ru.fizteh.fivt.storage.structured.ColumnFormatException; +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.storage.structured.TableProvider; + +public final class DataBaseTable implements TableProvider { + private String tableDir; + private Map tableInUse; + + private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); + private Lock readLock = readWriteLock.readLock(); + private Lock writeLock = readWriteLock.writeLock(); + + public DataBaseTable(String newTableDir) { + tableDir = newTableDir; + tableInUse = new HashMap(); + } + + private void checkName(final String name) { + if ((name == null) || name.trim().length() == 0) { + throw new IllegalArgumentException("Cannot create table! Wrong name!"); + } + + if (name.matches("[" + '"' + "'\\/:/*/?//|/.\\\\]+") || name.contains(File.separator) + || name.contains(".")) { + throw new RuntimeException("Wrong symbols in name!"); + } + } + + @Override + public Table createTable(final String tableName, List> columnTypes) throws IOException { + checkName(tableName); + + if (columnTypes == null || columnTypes.size() == 0) { + throw new IllegalArgumentException("wrong type (null)"); + } + + File file = new File(tableDir, tableName); + + writeLock.lock(); + try { + if (file.exists()) { + return null; + } + + if (!file.mkdir()) { + throw new MultiDataBaseException("Cannot create table " + tableName); + } + + DataBase table = new DataBase(file.toString(), this, columnTypes); + tableInUse.put(tableName, table); + return table; + } finally { + writeLock.unlock(); + } + } + + @Override + public void removeTable(final String tableName) throws IOException { + checkName(tableName); + + File file = new File(tableDir, tableName); + if (!file.exists()) { + throw new IllegalStateException("Table not exist already!"); + } + writeLock.lock(); + try { + if (!tableInUse.containsKey(tableName)) { + DataBase base = new DataBase(tableName, this, null); + base.drop(); + } else { + tableInUse.get(tableName).drop(); + tableInUse.remove(tableName); + } + if (!file.delete()) { + throw new DataBaseException("Cannot delete a file " + tableName); + } + } finally { + writeLock.unlock(); + } + } + + @Override + public Table getTable(String tableName) { + checkName(tableName); + + File file = new File(tableDir, tableName); + ; + + if ((!file.exists()) || (file.isFile())) { + return null; + } + + readLock.lock(); + try { + if (tableInUse.containsKey(tableName)) { + return tableInUse.get(tableName); + } + } finally { + readLock.unlock(); + } + + writeLock.lock(); + try { + DataBase table = new DataBase(file.toString(), this, null); + tableInUse.put(tableName, table); + return table; + } catch (IOException e) { + throw new DataBaseException(e.getMessage()); + } finally { + writeLock.unlock(); + } + + } + + @Override + public Storeable deserialize(Table table, String value) throws ParseException { + JSONArray json; + try { + json = new JSONArray(value); + } catch (JSONException e) { + throw new ParseException("Can't parse.", 0); + } + + List values = new ArrayList<>(); + for (int i = 0; i < json.length(); ++i) { + try { + values.add(json.get(i)); + } catch (JSONException e) { + throw new ParseException("Can't parse.", 0); + } + } + + Storeable storeable; + try { + storeable = createFor(table, values); + } catch (IndexOutOfBoundsException e) { + throw new ParseException("Invalid number of arguments!", 0); + } catch (ColumnFormatException e) { + throw new ParseException(e.getMessage(), 0); + } + + return storeable; + } + + @Override + public String serialize(Table table, Storeable value) throws ColumnFormatException { + return WorkWithJSON.serialize(table, value); + } + + @Override + public Storeable createFor(Table table) { + return new MyStoreable(table); + } + + @Override + public Storeable createFor(Table table, List values) throws ColumnFormatException, IndexOutOfBoundsException { + return new MyStoreable(table, values); + } + + @Override + public List getTableNames() { + List result = new ArrayList(); + Collections.addAll(result, new File(tableDir).list()); + return result; + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseWrongFileFormat.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseWrongFileFormat.java new file mode 100644 index 000000000..2eb6dc613 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseWrongFileFormat.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +public class DataBaseWrongFileFormat extends Error { + public DataBaseWrongFileFormat(final String message) { + super(message); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DbMain.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DbMain.java new file mode 100644 index 000000000..f9051921c --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DbMain.java @@ -0,0 +1,67 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +import java.io.IOException; + +import ru.fizteh.fivt.storage.structured.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.filemap.shell.Shell; +import ru.fizteh.fivt.students.kotsurba.storeable.*; + +public class DbMain { + private static Shell shell; + + private static void checkDbDir() { + if (!System.getProperties().containsKey("fizteh.db.dir")) { + System.err.println("Please set database directory!"); + System.err.println("-Dfizteh.db.dir="); + System.exit(1); + } + } + + private static void initShell() { + try { + shell = new Shell(); + + TableProviderFactory factory = new MyTableProviderFactory(); + Context context = new Context(factory.create(System.getProperty("fizteh.db.dir"))); + + shell.addCommand(new ShellDbPut(context)); + shell.addCommand(new ShellExit(context)); + shell.addCommand(new ShellDbGet(context)); + shell.addCommand(new ShellDbRemove(context)); + shell.addCommand(new ShellCreateTable(context)); + shell.addCommand(new ShellDropTable(context)); + shell.addCommand(new ShellUseTable(context)); + shell.addCommand(new ShellDbSize(context)); + shell.addCommand(new ShellDbCommit(context)); + shell.addCommand(new ShellDbRollback(context)); + shell.addCommand(new ShellDbList(context)); + shell.addCommand(new ShellDbShow(context)); + + } catch (IOException e) { + System.out.println("init shell failed!"); + System.exit(1); + } + } + + public static void main(final String[] args) { + try { + checkDbDir(); + initShell(); + + if (args.length > 0) { + ShellRunner.packetRun(shell, args); + } else { + ShellRunner.interactiveRun(shell); + } + + } catch (DataBaseException e) { + System.err.println(e.getMessage()); + System.exit(1); + } catch (ShellExitException e) { + System.exit(0); + } finally { + System.exit(0); + } + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/MultiDataBaseException.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/MultiDataBaseException.java new file mode 100644 index 000000000..5aa5df857 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/MultiDataBaseException.java @@ -0,0 +1,8 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +public class MultiDataBaseException extends Error { + public MultiDataBaseException(final String message) { + super(message); + } +} + diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/MySignature.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/MySignature.java new file mode 100644 index 000000000..fbfb9efb1 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/MySignature.java @@ -0,0 +1,106 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class MySignature { + static final String[] TYPES = {"int", "long", "byte", "float", "double", "boolean", "String"}; + static final Class[] CLASSES = {Integer.class, Long.class, Byte.class, Float.class, + Double.class, Boolean.class, String.class}; + + + public static List> getSignature(final String dir) throws IOException { + File file = new File(dir, "signature.tsv"); + if (!file.exists()) { + throw new IOException("Cannot find file:" + file.getCanonicalPath()); + } + + StringBuilder builder = new StringBuilder(); + + try (Scanner input = new Scanner(file)) { + if (!input.hasNext()) { + throw new IOException("Empty signature: " + file.getCanonicalPath()); + } + while (input.hasNext()) { + builder.append(input.next()).append(" "); + } + } + + String[] data = builder.toString().split(" "); + + List> result = new ArrayList<>(); + + if (data.length <= 0) { + throw new IOException("Empty signature: " + file.getCanonicalPath()); + } + + for (int i = 0; i < data.length; ++i) { + boolean flag = false; + for (int j = 0; j < TYPES.length; ++j) { + if (data[i].equals(TYPES[j])) { + result.add(CLASSES[j]); + flag = true; + break; + } + } + if (!flag) { + throw new IOException("Invalid type!"); + } + } + return result; + } + + public static void setSignature(final String dir, List> classesList) throws IOException { + try (PrintWriter output = new PrintWriter(new File(dir, "signature.tsv"))) { + for (int i = 0; i < classesList.size(); ++i) { + boolean flag = false; + for (int j = 0; j < CLASSES.length; ++j) { + if (CLASSES[j].equals(classesList.get(i))) { + output.write(TYPES[j]); + flag = true; + break; + } + } + if (!flag) { + throw new IllegalArgumentException("Bad TYPES!"); + } + if (i + 1 != classesList.size()) { + output.write(" "); + } + } + } + + } + + public static List> getTypes(final String str) throws IOException { + List> result = new ArrayList<>(); + byte[] s = str.trim().getBytes(); + if (!(s[0] == '(' && s[str.length() - 1] == ')')) { + throw new IOException("wrong type (no brackets)"); + } + for (int i = 1; i < str.length() - 1; ++i) { + if (s[i] == ' ') { + continue; + } + + boolean flag = false; + for (int j = 0; j < TYPES.length; ++j) { + if (new String(s, i, Math.min(TYPES[j].length(), str.length() - i)).equals(TYPES[j])) { + result.add(CLASSES[j]); + i += TYPES[j].length(); + flag = true; + break; + } + } + + if (!flag) { + throw new IOException("Cannot read type! position: " + i); + } + } + return result; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/MyStoreable.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/MyStoreable.java new file mode 100644 index 000000000..cf7a7e4c1 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/MyStoreable.java @@ -0,0 +1,231 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +import org.json.JSONObject; +import ru.fizteh.fivt.storage.structured.ColumnFormatException; +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; + +import java.util.ArrayList; +import java.util.List; + +public class MyStoreable implements Storeable { + private List> types = new ArrayList<>(); + private List values = new ArrayList<>(); + + public MyStoreable(Table table, List newValues) { + if (newValues == null) { + throw new IndexOutOfBoundsException("list of values cannot be null"); + } + if (newValues.size() != table.getColumnsCount()) { + throw new IndexOutOfBoundsException("invalid number of values"); + } + + for (int i = 0; i < newValues.size(); ++i) { + Object value = castTypes(table.getColumnType(i), newValues.get(i)); + if (value != null && value.getClass() != table.getColumnType(i)) { + throw new ColumnFormatException(newValues.get(i).toString() + " must be " + table.getColumnType(i) + + " but it is " + newValues.get(i).getClass()); + } + types.add(table.getColumnType(i)); + values.add(value); + } + } + + public MyStoreable(Table table) { + for (int i = 0; i < table.getColumnsCount(); ++i) { + types.add(table.getColumnType(i)); + values.add(null); + } + } + + + void checkBounds(int index) { + if (index < 0 || index >= types.size()) { + throw new IndexOutOfBoundsException("index out of bounds!"); + } + } + + void checkType(int index, Class value) { + if ((value != null) && (value != types.get(index))) { + throw new ColumnFormatException(); + } + } + + public int getSize() { + return types.size(); + } + + Object castTypes(Class type, Object value) { + if (value == null) { + return null; + } + + Class valueType = value.getClass(); + if (valueType == JSONObject.NULL.getClass() || JSONObject.NULL == value) { + return null; + } + + if (type == Integer.class) { + if (valueType == Integer.class) { + return value; + } + if (valueType == Byte.class) { + return new Integer((byte) value); + } + if (valueType == Long.class) { + long tmp = (long) value; + if (tmp <= Integer.MAX_VALUE && tmp >= Integer.MIN_VALUE) { + return (int) tmp; + } else { + throw new ColumnFormatException("Too big number for integer type: " + value.toString()); + } + } + throw new ColumnFormatException("Wrong type: " + valueType + " insted of Integer!"); + } + + if (type == Byte.class) { + if (valueType == Byte.class) { + return value; + } + if (valueType == Long.class || valueType == Integer.class) { + long tmp; + if (valueType == Long.class) { + tmp = (long) value; + } else { + tmp = (int) value; + } + if (tmp <= Byte.MAX_VALUE && tmp >= Byte.MIN_VALUE) { + return (byte) tmp; + } else { + throw new ColumnFormatException("Too big number for byte type: " + value.toString()); + } + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Byte!"); + } + + if (type == Long.class) { + if (valueType == Long.class) { + return value; + } + if (valueType == Byte.class) { + return new Long((byte) value); + } + if (valueType == Integer.class) { + return new Long((int) value); + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Long!"); + } + + if (type == Double.class) { + if (valueType == Integer.class) { + return new Double((int) value); + } + if (valueType == Byte.class) { + return new Double((byte) value); + } + if (valueType == Long.class) { + return new Double((long) value); + } + if (valueType == Float.class) { + return new Double((float) value); + } + if (valueType == Double.class) { + return value; + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Double"); + } + + if (type == Float.class) { + if (valueType == Integer.class) { + return new Float((int) value); + } + if (valueType == Byte.class) { + return new Float((byte) value); + } + if (valueType == Long.class) { + return new Float((long) value); + } + if (valueType == Double.class) { + return new Float((double) value); + } + if (value == Float.class) { + return value; + } + throw new ColumnFormatException("Wrong type: " + valueType + " instead of Float"); + } + + if (type == String.class) { + return value.toString(); + } + + return value; + } + + @Override + public void setColumnAt(int columnIndex, Object value) throws ColumnFormatException, IndexOutOfBoundsException { + if (value == null || value == JSONObject.NULL) { + value = null; + } + checkBounds(columnIndex); + value = castTypes(types.get(columnIndex), value); + if (value != null) { + checkType(columnIndex, value.getClass()); + } + values.set(columnIndex, value); + } + + @Override + public Object getColumnAt(int columnIndex) throws IndexOutOfBoundsException { + checkBounds(columnIndex); + return values.get(columnIndex); + } + + @Override + public Integer getIntAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Integer.class); + return (Integer) values.get(columnIndex); + } + + @Override + public Long getLongAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Long.class); + return (long) values.get(columnIndex); + } + + @Override + public Byte getByteAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Byte.class); + return (byte) values.get(columnIndex); + } + + @Override + public Float getFloatAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Float.class); + return (float) values.get(columnIndex); + } + + @Override + public Double getDoubleAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Double.class); + return (double) values.get(columnIndex); + } + + @Override + public Boolean getBooleanAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, Boolean.class); + return (boolean) values.get(columnIndex); + } + + @Override + public String getStringAt(int columnIndex) throws ColumnFormatException, IndexOutOfBoundsException { + checkBounds(columnIndex); + checkType(columnIndex, String.class); + return (String) values.get(columnIndex); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/MyTableProviderFactory.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/MyTableProviderFactory.java new file mode 100644 index 000000000..cf4a4c039 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/MyTableProviderFactory.java @@ -0,0 +1,31 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +import ru.fizteh.fivt.storage.structured.TableProvider; +import ru.fizteh.fivt.storage.structured.TableProviderFactory; + +import java.io.File; +import java.io.IOException; + +public class MyTableProviderFactory implements TableProviderFactory { + + @Override + public TableProvider create(String dir) throws IOException { + if (dir == null || dir.trim().equals("")) { + throw new IllegalArgumentException("Dir cannot be null"); + } + + File tableDirFile = new File(dir); + + if (!tableDirFile.exists()) { + if (!tableDirFile.mkdirs()) { + throw new IOException("Cannot create directory! " + tableDirFile.getCanonicalPath()); + } + } + + if (!tableDirFile.isDirectory()) { + throw new IllegalArgumentException("Wrong dir " + dir); + } + + return new DataBaseTable(dir); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/ShellExitException.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/ShellExitException.java new file mode 100644 index 000000000..b62050aa7 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/ShellExitException.java @@ -0,0 +1,7 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +public class ShellExitException extends RuntimeException { + public ShellExitException(final String message) { + super(message); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/WorkWithJSON.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/WorkWithJSON.java new file mode 100644 index 000000000..0b4ad6449 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/WorkWithJSON.java @@ -0,0 +1,55 @@ +package ru.fizteh.fivt.students.kotsurba.parallel; + +import org.json.JSONArray; +import org.json.JSONException; +import ru.fizteh.fivt.storage.structured.ColumnFormatException; +import ru.fizteh.fivt.storage.structured.Storeable; +import ru.fizteh.fivt.storage.structured.Table; + +public class WorkWithJSON { + + public static String serialize(Table table, Storeable value) throws ColumnFormatException { + + try { + value.getColumnAt(table.getColumnsCount()); + throw new ColumnFormatException("Too many columns!"); + } catch (IndexOutOfBoundsException e) { + //silent + } + + JSONArray array = new JSONArray(); + for (int i = 0; i < table.getColumnsCount(); ++i) { + try { + if (value.getColumnAt(i) == null || value.getColumnAt(i).getClass() == table.getColumnType(i)) { + array.put(value.getColumnAt(i)); + } else { + throw new ColumnFormatException("Column " + i + " has wrong type!"); + } + } catch (IndexOutOfBoundsException e) { + throw new ColumnFormatException("Too few columns!"); + } + } + return array.toString(); + } + + public static Storeable deserialize(Table table, String value) { + if (value == null) { + return null; + } + Storeable result = new MyStoreable(table); + JSONArray array = null; + try { + array = new JSONArray(value); + } catch (JSONException e) { + throw new IllegalArgumentException("can't deserialize"); + } + for (Integer i = 0; i < array.length(); ++i) { + try { + result.setColumnAt(i, array.get(i)); + } catch (JSONException e) { + throw new IllegalArgumentException("can't deserialize"); + } + } + return result; + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyParallelTest.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyParallelTest.java new file mode 100644 index 000000000..2da4685a6 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyParallelTest.java @@ -0,0 +1,172 @@ +package ru.fizteh.fivt.students.kotsurba.parallel.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.*; +import ru.fizteh.fivt.students.kotsurba.parallel.MyTableProviderFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + + +public class MyParallelTest { + private Table table; + static TableProviderFactory factory; + private TableProvider provider; + static List> types; + private ThreadPoolExecutor pool; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + + types = new ArrayList<>(); + types.add(String.class); + types.add(Integer.class); + } + + @Before + public void beforeTest() throws IOException { + provider = factory.create(folder.newFolder("folder").getCanonicalPath()); + table = provider.createTable("parallel", types); + + ThreadFactory demonFactory = new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setDaemon(true); + return thread; + } + }; + + pool = new ThreadPoolExecutor(1, 10, Long.MAX_VALUE, TimeUnit.NANOSECONDS, + new LinkedBlockingQueue(), demonFactory); + + } + + @After + public void afterTest() { + pool.shutdownNow(); + } + + public void storeableEquals(Storeable a, Storeable b) { + for (int i = 0; i < table.getColumnsCount(); ++i) { + Assert.assertEquals(a.getColumnAt(i), b.getColumnAt(i)); + } + } + + @Test(timeout = 15000) + public void concurrentPutCommitAndGet() throws Exception { + final List keyList = new ArrayList<>(); + + for (int i = 0; i < 1000; i++) { + keyList.add(Integer.toString(i)); + } + + Future firstHalf = pool.submit(new Callable() { + @Override + public Object call() throws Exception { + for (int i = 0; i < keyList.size() / 2; ++i) { + String key = keyList.get(i); + Assert.assertNull(table.put(key, provider.createFor(table, Arrays.asList(key, i)))); + Assert.assertEquals(1, table.commit()); + } + return null; + } + }); + + Future secondHalf = pool.submit(new Callable() { + @Override + public Object call() throws Exception { + for (int i = keyList.size() / 2; i < keyList.size(); ++i) { + String key = keyList.get(i); + Assert.assertNull(table.put(key, provider.createFor(table, Arrays.asList(key, i)))); + Assert.assertEquals(1, table.commit()); + } + return null; + } + }); + + firstHalf.get(); + secondHalf.get(); + + for (int i = 0; i < keyList.size(); ++i) { + String key = keyList.get(i); + storeableEquals(table.get(key), provider.createFor(table, Arrays.asList(key, i))); + } + } + + @Test(timeout = 15000) + public void concurrentPutBigCommitAndGet() throws Exception { + final List keyList = new ArrayList<>(); + + for (int i = 0; i < 1000; i++) { + keyList.add(Integer.toString(i)); + } + + Future firstHalf = pool.submit(new Callable() { + @Override + public Object call() throws Exception { + for (int i = 0; i < keyList.size() / 2; ++i) { + String key = keyList.get(i); + Assert.assertNull(table.put(key, provider.createFor(table, Arrays.asList(key, i)))); + Assert.assertEquals(1, table.commit()); + } + return null; + } + }); + + Future secondHalf = pool.submit(new Callable() { + @Override + public Object call() throws Exception { + for (int i = keyList.size() / 2; i < keyList.size(); ++i) { + String key = keyList.get(i); + Assert.assertNull(table.put(key, provider.createFor(table, Arrays.asList(key, i)))); + } + Assert.assertEquals(keyList.size() - keyList.size() / 2, table.commit()); + return null; + } + }); + + firstHalf.get(); + secondHalf.get(); + + for (int i = 0; i < keyList.size(); ++i) { + String key = keyList.get(i); + storeableEquals(table.get(key), provider.createFor(table, Arrays.asList(key, i))); + } + } + + @Test(timeout = 15000) + public void concurrentCreateTables() throws Exception { + + final AtomicInteger numberNulls = new AtomicInteger(0); + List> threads = new ArrayList<>(); + + for (int i = 0; i < 100; ++i) { + Future some = pool.submit(new Callable() { + @Override + public Object call() throws Exception { + if (provider.createTable("concurrent", types) == null) { + numberNulls.getAndIncrement(); + } + return null; + } + }); + threads.add(some); + } + for (int i = 0; i < threads.size(); ++i) { + threads.get(i).get(); + } + + Assert.assertEquals(numberNulls.get(), threads.size() - 1); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyStoreableTest.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyStoreableTest.java new file mode 100644 index 000000000..a76c28d68 --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyStoreableTest.java @@ -0,0 +1,172 @@ +package ru.fizteh.fivt.students.kotsurba.parallel.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.*; +import ru.fizteh.fivt.students.kotsurba.parallel.MyTableProviderFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +public class MyStoreableTest { + static Table table; + static TableProviderFactory factory; + static TableProvider provider; + static List> types; + static Storeable s; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void beforeTest() throws IOException { + provider = factory.create(folder.newFolder("folder").getCanonicalPath()); + types = new ArrayList<>(); + types.add(Integer.class); + types.add(String.class); + types.add(Byte.class); + types.add(Long.class); + types.add(Double.class); + types.add(Float.class); + types.add(Boolean.class); + table = provider.createTable("simple", types); + s = provider.createFor(table); + s.setColumnAt(0, 1); + s.setColumnAt(1, "1"); + s.setColumnAt(2, 1); + s.setColumnAt(3, 1); + s.setColumnAt(4, 1.11); + s.setColumnAt(5, 1.2); + s.setColumnAt(6, true); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testBoundsException() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(122, "12"); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testBoundsExceptionMore() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(-2, "44"); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatException() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, true); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionMore() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, "asdasd"); + storeable.getIntAt(0); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionLongInt() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(1, new Long("100000000000")); + storeable.getIntAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionDouble() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(1, new Double(0.0001)); + storeable.getIntAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionFloat() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(1, new Float(0.0201)); + storeable.getIntAt(1); + } + + @Test + public void testSetByteAtIntColumn() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, (byte) 11); + storeable.getIntAt(0); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionIntYo() { + s.getIntAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionByte() { + s.getByteAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionLong() { + s.getLongAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionDoubleYo() { + s.getDoubleAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionFloatYo() { + s.getFloatAt(1); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionString() { + s.getStringAt(0); + } + + @Test(expected = ColumnFormatException.class) + public void testColumnFormatExceptionBoolean() { + s.getBooleanAt(0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionInt() { + s.getIntAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionString() { + s.getStringAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionByte() { + s.getByteAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionLong() { + s.getLongAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionDouble() { + s.getDoubleAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionFloat() { + s.getFloatAt(100); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBoundsExceptionBoolean() { + s.getBooleanAt(100); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderFactoryTest.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderFactoryTest.java new file mode 100644 index 000000000..09069b70f --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderFactoryTest.java @@ -0,0 +1,31 @@ +package ru.fizteh.fivt.students.kotsurba.parallel.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.parallel.MyTableProviderFactory; + +import java.io.IOException; + +public class MyTableProviderFactoryTest { + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @Test(expected = IllegalArgumentException.class) + public void testCreateNull() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + factory.create(null); + } + + @Test + public void testCreateNotNull() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + Assert.assertNotNull(factory.create(folder.newFolder("folder").getCanonicalPath())); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateEmpty() throws IOException { + TableProviderFactory factory = new MyTableProviderFactory(); + Assert.assertNotNull(factory.create("")); + } +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderTest.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderTest.java new file mode 100644 index 000000000..64c7cf0fc --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableProviderTest.java @@ -0,0 +1,69 @@ +package ru.fizteh.fivt.students.kotsurba.parallel.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.Table; +import ru.fizteh.fivt.storage.structured.TableProvider; +import ru.fizteh.fivt.storage.structured.TableProviderFactory; +import ru.fizteh.fivt.students.kotsurba.parallel.MyTableProviderFactory; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class MyTableProviderTest { + static TableProviderFactory factory; + static TableProvider provider; + static String path; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void before() throws IOException { + path = folder.newFolder().getCanonicalPath(); + provider = factory.create(path); + Assert.assertNotNull(provider); + } + + @Test(expected = RuntimeException.class) + public void testSignature() { + new File(path, "test").mkdirs(); + provider.getTable("test"); + } + + @Test(expected = RuntimeException.class) + public void testSignatureEmpty() throws IOException { + File file = new File(path, "test"); + file.mkdirs(); + new File(file, "signature.tsv").createNewFile(); + provider.getTable("test"); + } + + @Test + public void testRemove() throws IOException { + List> types = new ArrayList<>(); + types.add(String.class); + types.add(Integer.class); + + Table table = provider.createTable("simple", types); + Assert.assertNotNull(table); + Assert.assertNotNull(provider.getTable("simple")); + provider.removeTable("simple"); + Assert.assertNull(provider.getTable("simple")); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyTypes() throws IOException { + List> types = new ArrayList<>(); + + Table table = provider.createTable("simple", types); + } + +} diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableTest.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableTest.java new file mode 100644 index 000000000..8b068e48b --- /dev/null +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/tests/MyTableTest.java @@ -0,0 +1,207 @@ +package ru.fizteh.fivt.students.kotsurba.parallel.tests; + +import org.junit.*; +import org.junit.rules.TemporaryFolder; +import ru.fizteh.fivt.storage.structured.*; +import ru.fizteh.fivt.students.kotsurba.parallel.MyTableProviderFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +public class MyTableTest { + static Table table; + static TableProviderFactory factory; + static TableProvider provider; + static List> types; + + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + + @BeforeClass + public static void beforeClass() { + factory = new MyTableProviderFactory(); + } + + @Before + public void beforeTest() throws IOException { + provider = factory.create(folder.newFolder("folder").getCanonicalPath()); + types = new ArrayList<>(); + types.add(String.class); + types.add(Integer.class); + + table = provider.createTable("simple", types); + + } + + public void storeableEquals(Storeable a, Storeable b) { + for (int i = 0; i < table.getColumnsCount(); ++i) { + Assert.assertEquals(a.getColumnAt(i), b.getColumnAt(i)); + } + } + + @Test + public void testGetPutSimple() throws IOException { + Storeable storeable = provider.createFor(table); + + storeable.setColumnAt(0, "new_value"); + storeable.setColumnAt(1, 100); + + Storeable old = provider.createFor(table); + old.setColumnAt(0, "new_value"); + old.setColumnAt(1, 100); + + Assert.assertNull(table.put("simple", storeable)); + storeableEquals(table.get("simple"), storeable); + + Assert.assertEquals(table.commit(), 1); + storeable.setColumnAt(0, "very_new"); + storeable.setColumnAt(1, null); + Assert.assertNull(table.put("null", storeable)); + storeableEquals(table.get("null"), storeable); + + storeableEquals(table.remove("null"), storeable); + storeableEquals(table.put("simple", storeable), old); + + Assert.assertEquals(table.rollback(), 1); + + storeableEquals(table.remove("simple"), old); + Assert.assertEquals(table.commit(), 1); + + Assert.assertNull(table.put("key", old)); + Assert.assertEquals(table.commit(), 1); + + storeableEquals(table.put("key", old), old); + Assert.assertEquals(table.commit(), 0); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutNullValue() { + table.put("simple", null); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutSpasedKey() { + Storeable storeable = provider.createFor(table); + + storeable.setColumnAt(0, "n e w_ v a lu e"); + storeable.setColumnAt(1, 100); + + table.put(" ", storeable); + } + + @Test + public void testPutGet() throws IOException { + types = new ArrayList<>(); + types.add(Long.class); + types.add(Long.class); + + Table table = provider.createTable("simple13424", types); + + Storeable storeable = provider.createFor(table); + + storeable.setColumnAt(0, (long) 123123123); + storeable.setColumnAt(1, (long) 100); + + Assert.assertNull(table.put("simple", storeable)); + storeableEquals(table.get("simple"), storeable); + } + + @Test(expected = ColumnFormatException.class) + public void testStoreableHasMoreLength() throws IOException { + List> types1 = new ArrayList<>(); + types1.add(Long.class); + types1.add(Boolean.class); + + Table table1 = provider.createTable("super1", types1); + + List> types2 = new ArrayList<>(); + types2.add(Long.class); + types2.add(Boolean.class); + types2.add(Byte.class); + Table table2 = provider.createTable("super2", types2); + + Storeable storeable = provider.createFor(table1); + + storeable.setColumnAt(0, (long) 123123123); + storeable.setColumnAt(1, true); + + Assert.assertNull(table1.put("simple", storeable)); + storeableEquals(table1.get("simple"), storeable); + + storeable = provider.createFor(table2); + + storeable.setColumnAt(0, 1); + storeable.setColumnAt(1, false); + storeable.setColumnAt(2, 1); + + Assert.assertNull(table2.put("simple", storeable)); + storeableEquals(table2.get("simple"), storeable); + + table1.put("sdasd", storeable); + } + + @Test(expected = ColumnFormatException.class) + public void testStoreableHasLessLength() throws IOException { + List> types1 = new ArrayList<>(); + types1.add(Long.class); + types1.add(Boolean.class); + + Table table1 = provider.createTable("super1", types1); + + List> types2 = new ArrayList<>(); + types2.add(Long.class); + types2.add(Boolean.class); + types2.add(Byte.class); + Table table2 = provider.createTable("super2", types2); + + Storeable storeable = provider.createFor(table1); + + storeable.setColumnAt(0, (long) 123123123); + storeable.setColumnAt(1, true); + + Assert.assertNull(table1.put("simple", storeable)); + storeableEquals(table1.get("simple"), storeable); + + Storeable storeable2 = provider.createFor(table2); + + storeable2.setColumnAt(0, 1); + storeable2.setColumnAt(1, false); + storeable2.setColumnAt(2, 1); + + Assert.assertNull(table2.put("simple", storeable2)); + storeableEquals(table2.get("simple"), storeable2); + + table2.put("sdasd", storeable); + } + + @Test + public void testEmptyStringInStoreable() { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, ""); + Assert.assertNull(table.put("abacaba", storeable)); + Assert.assertEquals(storeable.getStringAt(0), ""); + } + + @Test + public void testCommitRollback() throws IOException { + Storeable storeable = provider.createFor(table); + storeable.setColumnAt(0, ""); + Assert.assertNull(table.put("abacaba", storeable)); + Assert.assertEquals(table.commit(), 1); + Assert.assertNotNull(table.put("abacaba", storeable)); + Assert.assertNotNull(table.get("abacaba")); + Assert.assertEquals(table.commit(), 0); + Assert.assertEquals(table.rollback(), 0); + storeable.setColumnAt(0, "123"); + Assert.assertNotNull(table.put("abacaba", storeable)); + Assert.assertEquals(table.rollback(), 1); + Assert.assertNotNull(table.put("abacaba", storeable)); + Assert.assertEquals(table.commit(), 1); + Assert.assertNotNull(table.remove("abacaba")); + Assert.assertNull(table.put("abacaba", storeable)); + Assert.assertEquals(table.commit(), 0); + } +} From c89cf49c27824024f33be3413a8822dbc72ae2ac Mon Sep 17 00:00:00 2001 From: taftafa Date: Thu, 25 Dec 2014 05:11:40 +0400 Subject: [PATCH 13/13] Fixed parallel. --- src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java | 1 - src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java index bf9d6703e..cffc6d57c 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseFile.java @@ -11,7 +11,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; public class DataBaseFile { diff --git a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java index cbbc91b09..6a1660c43 100644 --- a/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java +++ b/src/ru/fizteh/fivt/students/kotsurba/parallel/DataBaseTable.java @@ -96,7 +96,6 @@ public Table getTable(String tableName) { checkName(tableName); File file = new File(tableDir, tableName); - ; if ((!file.exists()) || (file.isFile())) { return null;