diff --git a/09-Serialization/.idea/compiler.xml b/09-Serialization/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/09-Serialization/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/09-Serialization/.idea/copyright/profiles_settings.xml b/09-Serialization/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/09-Serialization/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/09-Serialization/.idea/misc.xml b/09-Serialization/.idea/misc.xml new file mode 100644 index 0000000..800fcd0 --- /dev/null +++ b/09-Serialization/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/10-DB/.idea/compiler.xml b/10-DB/.idea/compiler.xml new file mode 100644 index 0000000..ccb47a6 --- /dev/null +++ b/10-DB/.idea/compiler.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/copyright/profiles_settings.xml b/10-DB/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/10-DB/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/10-DB/.idea/gradle.xml b/10-DB/.idea/gradle.xml new file mode 100644 index 0000000..ab6e46d --- /dev/null +++ b/10-DB/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__cglib_cglib_nodep_2_2_2.xml b/10-DB/.idea/libraries/Gradle__cglib_cglib_nodep_2_2_2.xml new file mode 100644 index 0000000..eb17151 --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__cglib_cglib_nodep_2_2_2.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__com_thoughtworks_proxytoys_proxytoys_1_0.xml b/10-DB/.idea/libraries/Gradle__com_thoughtworks_proxytoys_proxytoys_1_0.xml new file mode 100644 index 0000000..b1005b8 --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__com_thoughtworks_proxytoys_proxytoys_1_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__junit_junit_4_11.xml b/10-DB/.idea/libraries/Gradle__junit_junit_4_11.xml new file mode 100644 index 0000000..dc26b34 --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__junit_junit_4_11.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml b/10-DB/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml new file mode 100644 index 0000000..8262f72 --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__org_jetbrains_annotations_15_0.xml b/10-DB/.idea/libraries/Gradle__org_jetbrains_annotations_15_0.xml new file mode 100644 index 0000000..ca78bcd --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__org_jetbrains_annotations_15_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__org_mongodb_bson_3_4_0.xml b/10-DB/.idea/libraries/Gradle__org_mongodb_bson_3_4_0.xml new file mode 100644 index 0000000..e525ce7 --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__org_mongodb_bson_3_4_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__org_mongodb_mongo_java_driver_3_2_2.xml b/10-DB/.idea/libraries/Gradle__org_mongodb_mongo_java_driver_3_2_2.xml new file mode 100644 index 0000000..82b40fb --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__org_mongodb_mongo_java_driver_3_2_2.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__org_mongodb_mongodb_driver_3_4_0.xml b/10-DB/.idea/libraries/Gradle__org_mongodb_mongodb_driver_3_4_0.xml new file mode 100644 index 0000000..747f9ae --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__org_mongodb_mongodb_driver_3_4_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__org_mongodb_mongodb_driver_core_3_4_0.xml b/10-DB/.idea/libraries/Gradle__org_mongodb_mongodb_driver_core_3_4_0.xml new file mode 100644 index 0000000..e0619e4 --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__org_mongodb_mongodb_driver_core_3_4_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/libraries/Gradle__org_mongodb_morphia_morphia_1_2_1.xml b/10-DB/.idea/libraries/Gradle__org_mongodb_morphia_morphia_1_2_1.xml new file mode 100644 index 0000000..34181a6 --- /dev/null +++ b/10-DB/.idea/libraries/Gradle__org_mongodb_morphia_morphia_1_2_1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/misc.xml b/10-DB/.idea/misc.xml new file mode 100644 index 0000000..9793229 --- /dev/null +++ b/10-DB/.idea/misc.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/modules.xml b/10-DB/.idea/modules.xml new file mode 100644 index 0000000..76a11df --- /dev/null +++ b/10-DB/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/modules/10-DB.iml b/10-DB/.idea/modules/10-DB.iml new file mode 100644 index 0000000..cb2b1ee --- /dev/null +++ b/10-DB/.idea/modules/10-DB.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/modules/10-DB_main.iml b/10-DB/.idea/modules/10-DB_main.iml new file mode 100644 index 0000000..1bbbb6e --- /dev/null +++ b/10-DB/.idea/modules/10-DB_main.iml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/.idea/modules/10-DB_test.iml b/10-DB/.idea/modules/10-DB_test.iml new file mode 100644 index 0000000..b9b69ca --- /dev/null +++ b/10-DB/.idea/modules/10-DB_test.iml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/10-DB/build.gradle b/10-DB/build.gradle new file mode 100644 index 0000000..9893ef0 --- /dev/null +++ b/10-DB/build.gradle @@ -0,0 +1,17 @@ +group 'ru.spbau.bachelor2015.veselov.hw10' +version '1.0-SNAPSHOT' + +apply plugin: 'java' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.11' + compile group: 'org.jetbrains', name: 'annotations', version: '15.0' + compile group: 'org.mongodb', name: 'mongodb-driver', version: '3.4.0' + compile group: 'org.mongodb.morphia', name: 'morphia', version: '1.2.1' +} diff --git a/10-DB/gradle/wrapper/gradle-wrapper.jar b/10-DB/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..ca78035 Binary files /dev/null and b/10-DB/gradle/wrapper/gradle-wrapper.jar differ diff --git a/10-DB/gradle/wrapper/gradle-wrapper.properties b/10-DB/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..c8ae6f7 --- /dev/null +++ b/10-DB/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Nov 28 21:38:34 MSK 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip diff --git a/10-DB/gradlew b/10-DB/gradlew new file mode 100755 index 0000000..27309d9 --- /dev/null +++ b/10-DB/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/10-DB/gradlew.bat b/10-DB/gradlew.bat new file mode 100644 index 0000000..f6d5974 --- /dev/null +++ b/10-DB/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/10-DB/settings.gradle b/10-DB/settings.gradle new file mode 100644 index 0000000..4b63503 --- /dev/null +++ b/10-DB/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = '10-DB' + diff --git a/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/DataBase.java b/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/DataBase.java new file mode 100644 index 0000000..aecf172 --- /dev/null +++ b/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/DataBase.java @@ -0,0 +1,155 @@ +package ru.spbau.bachelor2015.veselov.hw10; + +import com.mongodb.MongoClient; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.mongodb.morphia.Datastore; +import org.mongodb.morphia.Morphia; + +import java.util.List; + +/** + * A class which performs interaction with mongo database with a given name. + */ +public class DataBase { + private final Datastore datastore; + + /** + * Creates a link to mongo database which has a given name. + * + * @param databaseName a database name. + */ + public DataBase(String databaseName) { + Morphia morphia = new Morphia(); + morphia.mapPackage("ru.spbau.bachelor2015.veselov.hw10"); + + datastore = morphia.createDatastore(new MongoClient(), databaseName); + } + + /** + * Adds new entry to the database. Does nothing if entry with given name and phone already exists. + * + * @param name a person name. + * @param phone a phone number. + * @return ENTRY_ALREADY_EXISTS if entry already exists, OK otherwise. + */ + public @NotNull Respond addNewEntry(@NotNull String name, @NotNull String phone) { + if (getEntry(name, phone) != null) { + return Respond.ENTRY_ALREADY_EXISTS; + } + + datastore.save(new PhoneBookEntry(name, phone)); + return Respond.OK; + } + + /** + * Returns all entries with a given name. + * + * @param name a person name. + * @return a list of entries, where each entry's name equals to given one. + */ + public @NotNull List findByName(@NotNull String name) { + return datastore.createQuery(PhoneBookEntry.class).field("name").equal(name).asList(); + } + + /** + * Returns all entries with a given phone. + * + * @param phone a phone number. + * @return a list of entries, where each entry's phone equals to given one. + */ + public @NotNull List findByPhone(@NotNull String phone) { + return datastore.createQuery(PhoneBookEntry.class).field("phone").equal(phone).asList(); + } + + /** + * Deletes entry from the database. + * + * @param name a person name. + * @param phone a phone number. + * @return NO_SUCH_ENTRY if there is no entry with given name and phone in the database, OK otherwise. + */ + public @NotNull Respond deleteEntry(@NotNull String name, @NotNull String phone) { + PhoneBookEntry entry = getEntry(name, phone); + if (entry == null) { + return Respond.NO_SUCH_ENTRY; + } + + datastore.delete(entry); + return Respond.OK; + } + + /** + * Changes person name of a particular entry which determined by it's name and phone fields. + * + * @param oldName old person name. + * @param phone a phone number. + * @param newName new person name. + * @return NO_SUCH_ENTRY if there is no entry with given old name and phone in the database, ENTRY_ALREADY_EXISTS if + * there is an entry with given new name and phone in the database, OK otherwise. + */ + public @NotNull Respond changeName(@NotNull String oldName, @NotNull String phone, @NotNull String newName) { + PhoneBookEntry entry = getEntry(oldName, phone); + if (entry == null) { + return Respond.NO_SUCH_ENTRY; + } + + if (getEntry(newName, phone) != null) { + return Respond.ENTRY_ALREADY_EXISTS; + } + + datastore.save(new PhoneBookEntry(entry.getId(), newName, entry.getPhone())); + return Respond.OK; + } + + /** + * Changes phone number of a particular entry which determined by it's name and phone fields. + * + * @param name a person name. + * @param oldPhone old phone number. + * @param newPhone new phone number. + * @return NO_SUCH_ENTRY if there is no entry with given name and old phone in the database, ENTRY_ALREADY_EXISTS if + * there is an entry with given name and new phone in the database, OK otherwise. + */ + public @NotNull Respond changePhone(@NotNull String name, @NotNull String oldPhone, @NotNull String newPhone) { + PhoneBookEntry entry = getEntry(name, oldPhone); + if (entry == null) { + return Respond.NO_SUCH_ENTRY; + } + + if (getEntry(name, newPhone) != null) { + return Respond.ENTRY_ALREADY_EXISTS; + } + + datastore.save(new PhoneBookEntry(entry.getId(), entry.getName(), newPhone)); + return Respond.OK; + } + + /** + * Returns a list of all entries in the database. + */ + public @NotNull List getAllEntries() { + return datastore.createQuery(PhoneBookEntry.class).asList(); + } + + /** + * Drops the database. + */ + public void drop() { + datastore.getDB().dropDatabase(); + } + + private @Nullable PhoneBookEntry getEntry(@NotNull String name, @NotNull String phone) { + List list = datastore.createQuery(PhoneBookEntry.class) + .field("name").equal(name) + .field("phone").equal(phone) + .asList(); + if (list.isEmpty()) { + return null; + } + + return list.get(0); + } + + public enum Respond { OK, NO_SUCH_ENTRY, ENTRY_ALREADY_EXISTS }; +} diff --git a/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/Main.java b/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/Main.java new file mode 100644 index 0000000..1dfd1cb --- /dev/null +++ b/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/Main.java @@ -0,0 +1,161 @@ +package ru.spbau.bachelor2015.veselov.hw10; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Main class which implements interface of console application. + */ +public class Main { + private static final int promptCommand = 8; + + private static final String prompt = + "0 - quit\n" + + "1 - add new entry\n" + + "2 - find phones by name\n" + + "3 - find names by phone\n" + + "4 - delete entry name-phone\n" + + "5 - change name of name-phone entry\n" + + "6 - change phone of name-phone entry\n" + + "7 - print all entries\n" + + "8 - print this prompt"; + + private static final String incorrectCommandMsg = "Incorrect command. Enter " + promptCommand + " to see prompt."; + + /** + * Entry point of application. + * + * @param args no arguments required. + * @throws IOException any IOException which can occur during IO interaction with user. + */ + public static void main(String[] args) throws IOException { + System.out.println("Welcome to console phone book!"); + System.out.println("Please be careful, each token is read until end of line."); + System.out.println("Enter a command:"); + System.out.println(prompt); + + DataBase database = new DataBase("ru-spbau-bachelor2015-veselov-hw10"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in))) { + mainLoop: while (true) { + String commandString = in.readLine(); + + int command; + + try { + command = Integer.parseInt(commandString); + } catch (NumberFormatException e) { + System.out.println(incorrectCommandMsg); + continue; + } + + String name; + String newName; + String phone; + String newPhone; + switch (command) { + case 0: + break mainLoop; + + case 1: + System.out.println("Enter and to add new entry."); + + name = in.readLine(); + phone = in.readLine(); + if (database.addNewEntry(name, phone) == DataBase.Respond.ENTRY_ALREADY_EXISTS) { + System.out.println("Entry with such name and phone already exists."); + } + + break; + + case 2: + System.out.println("Enter to find phones of this person."); + + name = in.readLine(); + for (PhoneBookEntry entry : database.findByName(name)) { + System.out.println(entry.getPhone()); + } + + break; + + case 3: + System.out.println("Enter to find it's owners."); + + phone = in.readLine(); + for (PhoneBookEntry entry : database.findByPhone(phone)) { + System.out.println(entry.getName()); + } + + break; + + case 4: + System.out.println("Enter and to delete entry."); + + name = in.readLine(); + phone = in.readLine(); + if (database.deleteEntry(name, phone) == DataBase.Respond.NO_SUCH_ENTRY) { + System.out.println("Entry with such name and phone doesn't exist."); + } + + break; + + case 5: + System.out.println("Enter , and to change entry."); + + name = in.readLine(); + phone = in.readLine(); + newName = in.readLine(); + switch (database.changeName(name, phone, newName)) { + case NO_SUCH_ENTRY: + System.out.println("Entry with such name and phone doesn't exist."); + break; + + case ENTRY_ALREADY_EXISTS: + System.out.println("Entry with given new name and phone already exists."); + break; + + default: + break; + } + + break; + + case 6: + System.out.println("Enter , and to change entry."); + + name = in.readLine(); + phone = in.readLine(); + newPhone = in.readLine(); + switch (database.changePhone(name, phone, newPhone)) { + case NO_SUCH_ENTRY: + System.out.println("Entry with such name and phone doesn't exist."); + break; + + case ENTRY_ALREADY_EXISTS: + System.out.println("Entry with given name and new phone already exists."); + break; + + default: + break; + } + + break; + + case 7: + for (PhoneBookEntry entry : database.getAllEntries()) { + System.out.println("name: " + entry.getName() + ", phone: " + entry.getPhone()); + } + + break; + + case 8: + System.out.println(prompt); + break; + + default: + System.out.println(incorrectCommandMsg); + } + } + } + } +} diff --git a/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/PhoneBookEntry.java b/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/PhoneBookEntry.java new file mode 100644 index 0000000..fce0c79 --- /dev/null +++ b/10-DB/src/main/java/ru/spbau/bachelor2015/veselov/hw10/PhoneBookEntry.java @@ -0,0 +1,76 @@ +package ru.spbau.bachelor2015.veselov.hw10; + +import org.bson.types.ObjectId; +import org.jetbrains.annotations.NotNull; +import org.mongodb.morphia.annotations.Entity; +import org.mongodb.morphia.annotations.Id; + +/** + * Class which represents an entry in a phone book database. One entry consists of a name and a phone number. + * Format of a phone number isn't specified, so it's just a String field. + */ +@Entity +public class PhoneBookEntry { + @Id + private final ObjectId id; + + private final String name; + private final String phone; + + /** + * Creates an empty object. Used by morphia. + */ + public PhoneBookEntry() { + id = null; + name = null; + phone = null; + } + + /** + * Creates a brand new entry which has a unique new id. + * + * @param name a person name. + * @param phone a phone number. + */ + public PhoneBookEntry(@NotNull String name, @NotNull String phone) { + this.id = new ObjectId(); + + this.name = name; + this.phone = phone; + } + + /** + * Creates an entry with a specified id. Must be used to reference existing entry in a database. + * + * @param id an id of an entry in a database. + * @param name a person name. + * @param phone a phone number. + */ + public PhoneBookEntry(@NotNull ObjectId id, @NotNull String name, @NotNull String phone) { + this.id = id; + + this.name = name; + this.phone = phone; + } + + /** + * Returns id of an entry. + */ + public @NotNull ObjectId getId() { + return id; + } + + /** + * Returns a person name. + */ + public @NotNull String getName() { + return name; + } + + /** + * Returns a phone number. + */ + public @NotNull String getPhone() { + return phone; + } +} diff --git a/10-DB/src/test/java/ru/spbau/bachelor2015/veselov/hw10/DataBaseTest.java b/10-DB/src/test/java/ru/spbau/bachelor2015/veselov/hw10/DataBaseTest.java new file mode 100644 index 0000000..38ed686 --- /dev/null +++ b/10-DB/src/test/java/ru/spbau/bachelor2015/veselov/hw10/DataBaseTest.java @@ -0,0 +1,201 @@ +package ru.spbau.bachelor2015.veselov.hw10; + +import org.jetbrains.annotations.NotNull; +import org.junit.After; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class DataBaseTest { + private DataBase database = new DataBase("DataBase-test"); + + private final String name1 = "name1"; + + private final String name2 = "name2"; + + private final String name3 = "name3"; + + private final String phone1 = "phone1"; + + private final String phone2 = "phone2"; + + private final String phone3 = "phone3"; + + private final List allEntries = Arrays.asList( + new QuasiPhoneBookEntry(name1, phone1), + new QuasiPhoneBookEntry(name1, phone2), + new QuasiPhoneBookEntry(name2, phone1), + new QuasiPhoneBookEntry(name2, phone2)); + + private final List name1Entries = Arrays.asList( + new QuasiPhoneBookEntry(name1, phone1), + new QuasiPhoneBookEntry(name1, phone2)); + + private final List name2Entries = Arrays.asList( + new QuasiPhoneBookEntry(name2, phone1), + new QuasiPhoneBookEntry(name2, phone2)); + + private final List phone1Entries = Arrays.asList( + new QuasiPhoneBookEntry(name1, phone1), + new QuasiPhoneBookEntry(name2, phone1)); + + private final List phone2Entries = Arrays.asList( + new QuasiPhoneBookEntry(name1, phone2), + new QuasiPhoneBookEntry(name2, phone2)); + + private Comparator phoneBookEntryComparator = + (e1, e2) -> { + int nameComparisonResult = e1.getName().compareTo(e2.getName()); + if (nameComparisonResult != 0) { + return nameComparisonResult; + } + + return e1.getPhone().compareTo(e2.getPhone()); + }; + + @After + public void tearDown() throws Exception { + database.drop(); + } + + @Test + public void testAddition() throws Exception { + fillDataBase(); + + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.addNewEntry(name1, phone1)); + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.addNewEntry(name2, phone2)); + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.addNewEntry(name1, phone2)); + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.addNewEntry(name2, phone1)); + } + + @Test + public void testGetAllEntries() throws Exception { + assertQueryResult(database.getAllEntries(), Collections.emptyList()); + + fillDataBase(); + + assertQueryResult(database.getAllEntries(), allEntries); + } + + @Test + public void testFindByName() throws Exception { + fillDataBase(); + + assertQueryResult(database.findByName(name1), name1Entries); + assertQueryResult(database.findByName(name2), name2Entries); + assertQueryResult(database.findByName(name3), Collections.emptyList()); + } + + @Test + public void testFindByPhone() throws Exception { + fillDataBase(); + + assertQueryResult(database.findByPhone(phone1), phone1Entries); + assertQueryResult(database.findByPhone(phone2), phone2Entries); + assertQueryResult(database.findByPhone(phone3), Collections.emptyList()); + } + + @Test + public void testDeletion() throws Exception { + fillDataBase(); + + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.deleteEntry(name3, phone1)); + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.deleteEntry(name1, phone3)); + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.deleteEntry(name3, phone3)); + + assertEquals(DataBase.Respond.OK, database.deleteEntry(name1, phone1)); + assertEquals(DataBase.Respond.OK, database.deleteEntry(name1, phone2)); + assertQueryResult(database.getAllEntries(), name2Entries); + + assertEquals(DataBase.Respond.OK, database.addNewEntry(name1, phone1)); + assertEquals(DataBase.Respond.OK, database.addNewEntry(name1, phone2)); + assertQueryResult(database.getAllEntries(), allEntries); + } + + @Test + public void testChangeName() throws Exception { + fillDataBase(); + + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.changeName(name3, phone1, name1)); + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.changeName(name1, phone3, name1)); + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.changeName(name3, phone3, name1)); + + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.changeName(name1, phone1, name2)); + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.changeName(name2, phone2, name1)); + + assertEquals(DataBase.Respond.OK, database.changeName(name1, phone1, name3)); + assertEquals(DataBase.Respond.OK, database.changeName(name1, phone2, name3)); + + assertQueryResult(database.getAllEntries(), Arrays.asList( + new QuasiPhoneBookEntry(name2, phone1), + new QuasiPhoneBookEntry(name2, phone2), + new QuasiPhoneBookEntry(name3, phone1), + new QuasiPhoneBookEntry(name3, phone2))); + } + + @Test + public void testChangePhone() throws Exception { + fillDataBase(); + + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.changePhone(name1, phone3, phone1)); + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.changePhone(name3, phone1, phone3)); + assertEquals(DataBase.Respond.NO_SUCH_ENTRY, database.changePhone(name3, phone3, phone1)); + + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.changePhone(name1, phone1, phone2)); + assertEquals(DataBase.Respond.ENTRY_ALREADY_EXISTS, database.changePhone(name2, phone2, phone1)); + + assertEquals(DataBase.Respond.OK, database.changePhone(name1, phone1, phone3)); + assertEquals(DataBase.Respond.OK, database.changePhone(name2, phone1, phone3)); + + assertQueryResult(database.getAllEntries(), Arrays.asList( + new QuasiPhoneBookEntry(name1, phone2), + new QuasiPhoneBookEntry(name1, phone3), + new QuasiPhoneBookEntry(name2, phone2), + new QuasiPhoneBookEntry(name2, phone3))); + } + + private void assertQueryResult(@NotNull List result, @NotNull List expected) { + Collections.sort(result, phoneBookEntryComparator); + assertEquals(expected, result); + } + + private void fillDataBase() { + for (QuasiPhoneBookEntry entry : allEntries) { + assertEquals(DataBase.Respond.OK, database.addNewEntry(entry.getName(), entry.getPhone())); + } + } + + private static class QuasiPhoneBookEntry { + private final String name; + + private final String phone; + + public QuasiPhoneBookEntry(@NotNull String name, @NotNull String phone) { + this.name = name; + this.phone = phone; + } + + public @NotNull String getName() { + return name; + } + + public @NotNull String getPhone() { + return phone; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof PhoneBookEntry)) { + return false; + } + + PhoneBookEntry other = (PhoneBookEntry) object; + return name.equals(other.getName()) && phone.equals(other.getPhone()); + } + } +}