From 494e0f9f9a3bd91f3c26281b76bc2a4bcca47a8e Mon Sep 17 00:00:00 2001 From: Vladislav Kostylev Date: Sat, 29 Dec 2018 10:31:53 +0300 Subject: [PATCH 1/4] Stage 2 --- .../database/clientside/Client.java | 33 ++++++++++++-- .../database/serverside/Server.java | 44 ++++++++++++++++++- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/client/src/main/java/org/hyperskill/database/clientside/Client.java b/client/src/main/java/org/hyperskill/database/clientside/Client.java index 8659582..aa7644a 100644 --- a/client/src/main/java/org/hyperskill/database/clientside/Client.java +++ b/client/src/main/java/org/hyperskill/database/clientside/Client.java @@ -1,7 +1,34 @@ package org.hyperskill.database.clientside; +import java.io.*; +import java.net.*; +import java.util.*; + public class Client { - public static void main(String[] args) { - System.out.println("Hello World!"); - } + private static final String SERVER_ADDRESS = "127.0.0.1"; + private static final int SERVER_PORT = 34522; + + public static void main(String[] args) { + try ( + Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT); + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()) + ) { + System.out.println("Client started!"); + while (true) { + System.out.print("Give me a record # "); + Scanner scanner = new Scanner(System.in); + String msg = scanner.nextLine(); + + output.writeUTF(msg); // sending message to the server + System.out.println("Sent: " + msg); + String receivedMsg = input.readUTF(); // response message + System.out.println("Recieved: " + receivedMsg); + + + } + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/server/src/main/java/org/hyperskill/database/serverside/Server.java b/server/src/main/java/org/hyperskill/database/serverside/Server.java index 122143d..d703844 100644 --- a/server/src/main/java/org/hyperskill/database/serverside/Server.java +++ b/server/src/main/java/org/hyperskill/database/serverside/Server.java @@ -1,7 +1,49 @@ package org.hyperskill.database.serverside; +import java.io.*; +import java.net.*; +import java.util.*; + +//java -cp target/...jar com.kkk.app + public class Server { + private static final int PORT = 34522; + public static void main(String[] args) { - System.out.println("Hello World!"); + try (ServerSocket server = new ServerSocket(PORT)) { + while (true) { + Session session = new Session(server.accept()); + session.run(); // it does not block this thread + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} + +class Session { + private final Socket socket; + + public Session(Socket socketForClient) { + this.socket = socketForClient; + } + + public void run() { + try ( + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()) + ) { + System.out.println("Server started!"); + while(true) { + String msg = input.readUTF(); + + System.out.println("Recieved: " + msg); + output.writeUTF(msg); + System.out.println("Sent: " + msg); + + } + } catch (IOException e) { + e.printStackTrace(); + } } } From 11b3117f79441c55df4df618b392af96b7263a43 Mon Sep 17 00:00:00 2001 From: Vladislav Kostylev Date: Tue, 8 Jan 2019 18:53:21 +0300 Subject: [PATCH 2/4] Stage #3 implemented --- .../database/clientside/Client.java | 89 +++++++++++++------ .../database/clientside/Commands.java | 14 +++ .../database/clientside/PositiveInteger.java | 14 +++ .../database/serverside/Server.java | 58 +++++------- .../database/serverside/Storage.java | 39 ++++++++ 5 files changed, 149 insertions(+), 65 deletions(-) create mode 100644 client/src/main/java/org/hyperskill/database/clientside/Commands.java create mode 100644 client/src/main/java/org/hyperskill/database/clientside/PositiveInteger.java create mode 100644 server/src/main/java/org/hyperskill/database/serverside/Storage.java diff --git a/client/src/main/java/org/hyperskill/database/clientside/Client.java b/client/src/main/java/org/hyperskill/database/clientside/Client.java index aa7644a..056d70a 100644 --- a/client/src/main/java/org/hyperskill/database/clientside/Client.java +++ b/client/src/main/java/org/hyperskill/database/clientside/Client.java @@ -1,34 +1,65 @@ package org.hyperskill.database.clientside; -import java.io.*; -import java.net.*; -import java.util.*; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; public class Client { - private static final String SERVER_ADDRESS = "127.0.0.1"; - private static final int SERVER_PORT = 34522; - - public static void main(String[] args) { - try ( - Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT); - DataInputStream input = new DataInputStream(socket.getInputStream()); - DataOutputStream output = new DataOutputStream(socket.getOutputStream()) - ) { - System.out.println("Client started!"); - while (true) { - System.out.print("Give me a record # "); - Scanner scanner = new Scanner(System.in); - String msg = scanner.nextLine(); - - output.writeUTF(msg); // sending message to the server - System.out.println("Sent: " + msg); - String receivedMsg = input.readUTF(); // response message - System.out.println("Recieved: " + receivedMsg); - - - } - } catch (IOException e) { - e.printStackTrace(); - } - } + @Parameter(names = {"-host", "-ip"}, description = "IP address") + String host; + + @Parameter(names = {"-port"}, description = "Port", validateWith = PositiveInteger.class) + int port; + + @Parameter(names = "-t", description = "Command", validateWith = Commands.class) + String command; + + @Parameter(names = "-m", description = "Text to save") + String text; + + @Parameter(names = "-i", description = "Index", validateWith = PositiveInteger.class) + int index; + + public static void main(String... argv) { + Client client = new Client(); + JCommander.newBuilder().addObject(client).build().parse(argv); + + if (argv.length < 8) { + System.err.println( + "Usage: java -jar client.jar -ip -port -t -i [-m ]"); + System.exit(1); + } + + try ( + Socket socket = new Socket(client.host, client.port); + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()) + ) { + if (client.command.equals("set")) { + if (client.text != null) { + output.writeUTF(client.command + " " + client.index + " " + client.text); + System.out.println("Sent: " + client.command + " " + client.index + " " + client.text); + } else { + System.err.println("Text cannot be empty"); + System.exit(1); + } + } else { + output.writeUTF(client.command + " " + client.index); + System.out.println("Sent: " + client.command + " " + client.index); + } + String receivedMsg = input.readUTF(); // response message + System.out.println("Received: " + receivedMsg); + } catch (IOException e) { + e.printStackTrace(); + } + } } + + + + + diff --git a/client/src/main/java/org/hyperskill/database/clientside/Commands.java b/client/src/main/java/org/hyperskill/database/clientside/Commands.java new file mode 100644 index 0000000..a6e32dd --- /dev/null +++ b/client/src/main/java/org/hyperskill/database/clientside/Commands.java @@ -0,0 +1,14 @@ +package org.hyperskill.database.clientside; + +import com.beust.jcommander.IParameterValidator; +import com.beust.jcommander.ParameterException; + +public class Commands implements IParameterValidator { + public void validate(String name, String value) + throws ParameterException { + value = value.trim().toLowerCase(); + if (!(value.equals("set") || value.equals("get") || value.equals("delete"))) { + throw new ParameterException("Parameter " + name + " should be set/get/delete (found " + value + ")"); + } + } +} diff --git a/client/src/main/java/org/hyperskill/database/clientside/PositiveInteger.java b/client/src/main/java/org/hyperskill/database/clientside/PositiveInteger.java new file mode 100644 index 0000000..09661a5 --- /dev/null +++ b/client/src/main/java/org/hyperskill/database/clientside/PositiveInteger.java @@ -0,0 +1,14 @@ +package org.hyperskill.database.clientside; + +import com.beust.jcommander.IParameterValidator; +import com.beust.jcommander.ParameterException; + +public class PositiveInteger implements IParameterValidator { + public void validate(String name, String value) + throws ParameterException { + int n = Integer.parseInt(value); + if (n < 0) { + throw new ParameterException("Parameter " + name + " should be positive (found " + value + ")"); + } + } +} diff --git a/server/src/main/java/org/hyperskill/database/serverside/Server.java b/server/src/main/java/org/hyperskill/database/serverside/Server.java index d703844..9003569 100644 --- a/server/src/main/java/org/hyperskill/database/serverside/Server.java +++ b/server/src/main/java/org/hyperskill/database/serverside/Server.java @@ -1,46 +1,32 @@ package org.hyperskill.database.serverside; -import java.io.*; -import java.net.*; -import java.util.*; - -//java -cp target/...jar com.kkk.app +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; public class Server { - private static final int PORT = 34522; - public static void main(String[] args) { - try (ServerSocket server = new ServerSocket(PORT)) { - while (true) { - Session session = new Session(server.accept()); - session.run(); // it does not block this thread - } - } catch (IOException e) { - e.printStackTrace(); + if (args.length != 1) { + System.err.println("Usage: java Server "); + System.exit(1); } - } -} - -class Session { - private final Socket socket; - - public Session(Socket socketForClient) { - this.socket = socketForClient; - } - - public void run() { - try ( - DataInputStream input = new DataInputStream(socket.getInputStream()); - DataOutputStream output = new DataOutputStream(socket.getOutputStream()) - ) { - System.out.println("Server started!"); - while(true) { - String msg = input.readUTF(); - - System.out.println("Recieved: " + msg); - output.writeUTF(msg); - System.out.println("Sent: " + msg); + int portNumber = Integer.parseInt(args[0]); + Protocol protocol = new Protocol(); + try (ServerSocket server = new ServerSocket(portNumber)) { + while (true) { + try ( + Socket socket = server.accept(); // accepting a new client + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()) + ) { + String inputLine, outputLine; + inputLine = input.readUTF(); // reading a message + outputLine = protocol.processInput(inputLine); + output.writeUTF(outputLine); // resend it to the client + } } } catch (IOException e) { e.printStackTrace(); diff --git a/server/src/main/java/org/hyperskill/database/serverside/Storage.java b/server/src/main/java/org/hyperskill/database/serverside/Storage.java new file mode 100644 index 0000000..1ec825a --- /dev/null +++ b/server/src/main/java/org/hyperskill/database/serverside/Storage.java @@ -0,0 +1,39 @@ +package org.hyperskill.database.serverside; + +public class Storage { + private static final int SIZE = 1000; + private String[] storage = new String[SIZE]; + + private boolean indexInRange(int index) { + return index > 0 && index <= SIZE; + } + + void set(int index, String str) { + if (indexInRange(index)) { + storage[index - 1] = str; + } else { + throw new IllegalArgumentException("Size is " + SIZE + ", got index " + index); + } + } + + String get(int index) { + String result; + if (indexInRange(index)) { + result = storage[index - 1]; + if (!result.equals("")) { + return result; + } + } else { + throw new IllegalArgumentException("Size is " + SIZE + ", got index " + index); + } + return null; + } + + void delete(int index) { + if (indexInRange(index)) { + storage[index - 1] = ""; + } else { + throw new IllegalArgumentException("Size is " + SIZE + ", got index " + index); + } + } +} From cea29ba62ff05beba7ddf595768f12669f1590b5 Mon Sep 17 00:00:00 2001 From: Vladislav Kostylev Date: Thu, 10 Jan 2019 10:19:26 +0300 Subject: [PATCH 3/4] Stage #4 implemented --- .../database/clientside/Client.java | 23 ++++------ .../hyperskill/database/common/Request.java | 46 +++++++++++++++++++ .../hyperskill/database/common/Response.java | 27 +++++++++++ server/pom.xml | 8 ++-- .../database/serverside/JsonProtocol.java | 41 +++++++++++++++++ .../database/serverside/JsonStorage.java | 22 +++++++++ .../database/serverside/Server.java | 13 ++++-- .../database/serverside/Storage.java | 39 ---------------- 8 files changed, 159 insertions(+), 60 deletions(-) create mode 100644 common/src/main/java/org/hyperskill/database/common/Request.java create mode 100644 common/src/main/java/org/hyperskill/database/common/Response.java create mode 100644 server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java create mode 100644 server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java delete mode 100644 server/src/main/java/org/hyperskill/database/serverside/Storage.java diff --git a/client/src/main/java/org/hyperskill/database/clientside/Client.java b/client/src/main/java/org/hyperskill/database/clientside/Client.java index 056d70a..e044bd7 100644 --- a/client/src/main/java/org/hyperskill/database/clientside/Client.java +++ b/client/src/main/java/org/hyperskill/database/clientside/Client.java @@ -2,6 +2,8 @@ import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; +import com.google.gson.Gson; +import org.hyperskill.database.common.Request; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -21,8 +23,8 @@ public class Client { @Parameter(names = "-m", description = "Text to save") String text; - @Parameter(names = "-i", description = "Index", validateWith = PositiveInteger.class) - int index; + @Parameter(names = "-i", description = "Index") + String index; public static void main(String... argv) { Client client = new Client(); @@ -39,18 +41,11 @@ public static void main(String... argv) { DataInputStream input = new DataInputStream(socket.getInputStream()); DataOutputStream output = new DataOutputStream(socket.getOutputStream()) ) { - if (client.command.equals("set")) { - if (client.text != null) { - output.writeUTF(client.command + " " + client.index + " " + client.text); - System.out.println("Sent: " + client.command + " " + client.index + " " + client.text); - } else { - System.err.println("Text cannot be empty"); - System.exit(1); - } - } else { - output.writeUTF(client.command + " " + client.index); - System.out.println("Sent: " + client.command + " " + client.index); - } + Request request = new Request(client.command, client.index, client.text); + Gson gson = new Gson(); + String out = gson.toJson(request); + output.writeUTF(out); + System.out.println("Sent: " + out); String receivedMsg = input.readUTF(); // response message System.out.println("Received: " + receivedMsg); } catch (IOException e) { diff --git a/common/src/main/java/org/hyperskill/database/common/Request.java b/common/src/main/java/org/hyperskill/database/common/Request.java new file mode 100644 index 0000000..95292ed --- /dev/null +++ b/common/src/main/java/org/hyperskill/database/common/Request.java @@ -0,0 +1,46 @@ +package org.hyperskill.database.common; + +import java.util.Objects; + +public class Request { + public enum TYPE {SET, GET, DELETE} + private TYPE type; + private String key; + private String value; + + public Request(String type, String key, String value) { + Objects.requireNonNull(type); + Objects.requireNonNull(key); + + switch (type.trim().toLowerCase()) { + case "set": + this.type = TYPE.SET; + break; + case "get": + this.type = TYPE.GET; + break; + case "delete": + this.type = TYPE.DELETE; + break; + default: + throw new IllegalArgumentException(type + " is not allowed command"); + } + if (this.type == TYPE.SET && value == null) { + throw new IllegalArgumentException("Set command requires value, got null"); + } + this.key = key; + this.value = value; + } + + public TYPE getType() { + return type; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } +} diff --git a/common/src/main/java/org/hyperskill/database/common/Response.java b/common/src/main/java/org/hyperskill/database/common/Response.java new file mode 100644 index 0000000..9b7083a --- /dev/null +++ b/common/src/main/java/org/hyperskill/database/common/Response.java @@ -0,0 +1,27 @@ +package org.hyperskill.database.common; + +public class Response { + public enum TYPE {OK, FAIL} + private TYPE type; + private String value; + private String reason; + + public Response(String type, String value, String reason) { + switch (type.trim().toLowerCase()) { + case "ok": + this.type = TYPE.OK; + break; + case "fail": + this.type = TYPE.FAIL; + break; + default: + throw new IllegalArgumentException(type + " is not allowed command"); + } + + if (this.type == TYPE.FAIL && reason == null) { + throw new IllegalArgumentException("FAIL response requires reason, got null"); + } + this.reason = reason; + this.value = value; + } +} diff --git a/server/pom.xml b/server/pom.xml index 144a705..ee6d69d 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -18,10 +18,6 @@ - - com.google.code.gson - gson - com.beust jcommander @@ -30,6 +26,10 @@ org.hyperskill.database common + + com.google.code.gson + gson + diff --git a/server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java b/server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java new file mode 100644 index 0000000..2315b40 --- /dev/null +++ b/server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java @@ -0,0 +1,41 @@ +package org.hyperskill.database.serverside; + +import com.google.gson.JsonElement; +import org.hyperskill.database.common.Request; +import org.hyperskill.database.common.Response; + +import java.util.Objects; + +public class JsonProtocol { + JsonStorage storage = new JsonStorage(); + + public Response processInput(Request input) { + Objects.requireNonNull(input, "Request cannot be empty in JsonProtocol.processInput"); + Response response; + switch (input.getType()) { + case GET: + JsonElement result = storage.get(input.getKey()); + if (result != null) { + response = new Response("ok", result.toString(), null); + } else { + response = new Response("fail", null, "No such key"); + } + break; + case SET: + storage.set(input.getKey(), input.getValue()); + response = new Response("Ok", null, null); + break; + case DELETE: + if (storage.get(input.getKey()) != null) { + storage.delete(input.getKey()); + response = new Response("ok", null, null); + } else { + response = new Response("fail", null, "No such key"); + } + break; + default: + throw new IllegalArgumentException(input.getType().toString() + " is not allowed command"); + } + return response; + } +} diff --git a/server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java b/server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java new file mode 100644 index 0000000..d0c935d --- /dev/null +++ b/server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java @@ -0,0 +1,22 @@ +package org.hyperskill.database.serverside; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public class JsonStorage { + + private JsonObject storage = new JsonObject(); + + public void set(String property, String value) { + storage.addProperty(property, value); + } + + public JsonElement get(String name) { + return storage.get(name); + } + + public void delete(String name) { + storage.remove(name); + } + +} diff --git a/server/src/main/java/org/hyperskill/database/serverside/Server.java b/server/src/main/java/org/hyperskill/database/serverside/Server.java index 9003569..ed2c6ac 100644 --- a/server/src/main/java/org/hyperskill/database/serverside/Server.java +++ b/server/src/main/java/org/hyperskill/database/serverside/Server.java @@ -1,5 +1,9 @@ package org.hyperskill.database.serverside; +import com.google.gson.Gson; +import org.hyperskill.database.common.Request; +import org.hyperskill.database.common.Response; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -14,7 +18,7 @@ public static void main(String[] args) { } int portNumber = Integer.parseInt(args[0]); - Protocol protocol = new Protocol(); + JsonProtocol protocol = new JsonProtocol(); try (ServerSocket server = new ServerSocket(portNumber)) { while (true) { try ( @@ -24,8 +28,11 @@ public static void main(String[] args) { ) { String inputLine, outputLine; inputLine = input.readUTF(); // reading a message - outputLine = protocol.processInput(inputLine); - output.writeUTF(outputLine); // resend it to the client + Gson gson = new Gson(); + Request request = gson.fromJson(inputLine, Request.class); + Response response = protocol.processInput(request); + String out = gson.toJson(response); + output.writeUTF(out); // resend it to the client } } } catch (IOException e) { diff --git a/server/src/main/java/org/hyperskill/database/serverside/Storage.java b/server/src/main/java/org/hyperskill/database/serverside/Storage.java deleted file mode 100644 index 1ec825a..0000000 --- a/server/src/main/java/org/hyperskill/database/serverside/Storage.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.hyperskill.database.serverside; - -public class Storage { - private static final int SIZE = 1000; - private String[] storage = new String[SIZE]; - - private boolean indexInRange(int index) { - return index > 0 && index <= SIZE; - } - - void set(int index, String str) { - if (indexInRange(index)) { - storage[index - 1] = str; - } else { - throw new IllegalArgumentException("Size is " + SIZE + ", got index " + index); - } - } - - String get(int index) { - String result; - if (indexInRange(index)) { - result = storage[index - 1]; - if (!result.equals("")) { - return result; - } - } else { - throw new IllegalArgumentException("Size is " + SIZE + ", got index " + index); - } - return null; - } - - void delete(int index) { - if (indexInRange(index)) { - storage[index - 1] = ""; - } else { - throw new IllegalArgumentException("Size is " + SIZE + ", got index " + index); - } - } -} From 0abf2f59e9d72049336e91d4c68bd6dc2d340f70 Mon Sep 17 00:00:00 2001 From: Vladislav Kostylev Date: Fri, 25 Jan 2019 19:58:54 +0100 Subject: [PATCH 4/4] Stage #5 implemented --- .gitignore | 34 ------- .../database/clientside/Client.java | 28 +++++- .../hyperskill/database/common/Request.java | 31 +++--- .../hyperskill/database/common/Response.java | 21 ++++ .../org/hyperskill/database/common/Util.java | 58 +++++++++++ .../database/serverside/JsonProtocol.java | 30 ------ .../database/serverside/JsonStorage.java | 73 ++++++++++++-- .../database/serverside/NetworkService.java | 96 +++++++++++++++++++ .../database/serverside/Server.java | 53 +++++++--- 9 files changed, 325 insertions(+), 99 deletions(-) delete mode 100644 .gitignore create mode 100644 common/src/main/java/org/hyperskill/database/common/Util.java create mode 100644 server/src/main/java/org/hyperskill/database/serverside/NetworkService.java diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 51216a5..0000000 --- a/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -#common -target/ -out/ -classes/ - -#IDEA Project Files -*iml -*iws -.idea -*ipr \ No newline at end of file diff --git a/client/src/main/java/org/hyperskill/database/clientside/Client.java b/client/src/main/java/org/hyperskill/database/clientside/Client.java index e044bd7..2b0e814 100644 --- a/client/src/main/java/org/hyperskill/database/clientside/Client.java +++ b/client/src/main/java/org/hyperskill/database/clientside/Client.java @@ -4,6 +4,8 @@ import com.beust.jcommander.Parameter; import com.google.gson.Gson; import org.hyperskill.database.common.Request; +import org.hyperskill.database.common.Response; +import org.hyperskill.database.common.Util; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -17,6 +19,7 @@ public class Client { @Parameter(names = {"-port"}, description = "Port", validateWith = PositiveInteger.class) int port; + /* @Parameter(names = "-t", description = "Command", validateWith = Commands.class) String command; @@ -25,14 +28,21 @@ public class Client { @Parameter(names = "-i", description = "Index") String index; + */ + + @Parameter(names = "-in", description = "Input file") + String inputFile; + + @Parameter(names = "-out", description = "Output file") + String outputFile; public static void main(String... argv) { Client client = new Client(); JCommander.newBuilder().addObject(client).build().parse(argv); - if (argv.length < 8) { + if (argv.length < 6) { System.err.println( - "Usage: java -jar client.jar -ip -port -t -i [-m ]"); + "Usage: java -jar client.jar -ip -port -in [-out ]"); System.exit(1); } @@ -41,13 +51,25 @@ public static void main(String... argv) { DataInputStream input = new DataInputStream(socket.getInputStream()); DataOutputStream output = new DataOutputStream(socket.getOutputStream()) ) { - Request request = new Request(client.command, client.index, client.text); + System.out.println("ifile" + client.inputFile); + + Request request = Util.read(client.inputFile); Gson gson = new Gson(); String out = gson.toJson(request); output.writeUTF(out); System.out.println("Sent: " + out); String receivedMsg = input.readUTF(); // response message System.out.println("Received: " + receivedMsg); + Response response = gson.fromJson(receivedMsg, Response.class); + if (response.isOk()) { + System.out.println("Request was successful"); + if (client.outputFile != null && request.getType()== Request.TYPE.GET){ + System.out.println("Value saved to " + client.outputFile); + Util.write(response, client.outputFile); + } + } else { + System.out.println("Request was not successful"); + } } catch (IOException e) { e.printStackTrace(); } diff --git a/common/src/main/java/org/hyperskill/database/common/Request.java b/common/src/main/java/org/hyperskill/database/common/Request.java index 95292ed..178a89c 100644 --- a/common/src/main/java/org/hyperskill/database/common/Request.java +++ b/common/src/main/java/org/hyperskill/database/common/Request.java @@ -8,23 +8,12 @@ public enum TYPE {SET, GET, DELETE} private String key; private String value; - public Request(String type, String key, String value) { + public Request(String type, String key, String value) throws IllegalArgumentException { Objects.requireNonNull(type); Objects.requireNonNull(key); - switch (type.trim().toLowerCase()) { - case "set": - this.type = TYPE.SET; - break; - case "get": - this.type = TYPE.GET; - break; - case "delete": - this.type = TYPE.DELETE; - break; - default: - throw new IllegalArgumentException(type + " is not allowed command"); - } + this.type = validateCommand(type); + if (this.type == TYPE.SET && value == null) { throw new IllegalArgumentException("Set command requires value, got null"); } @@ -43,4 +32,18 @@ public String getKey() { public String getValue() { return value; } + + public static TYPE validateCommand(String word) { + switch (word.trim().toLowerCase()) { + case "set": + return TYPE.SET; + case "get": + return TYPE.GET; + case "delete": + return TYPE.DELETE; + default: + throw new IllegalArgumentException(word + " is not allowed command"); + } + + } } diff --git a/common/src/main/java/org/hyperskill/database/common/Response.java b/common/src/main/java/org/hyperskill/database/common/Response.java index 9b7083a..a7e901d 100644 --- a/common/src/main/java/org/hyperskill/database/common/Response.java +++ b/common/src/main/java/org/hyperskill/database/common/Response.java @@ -2,7 +2,28 @@ public class Response { public enum TYPE {OK, FAIL} + + public boolean isOk() { + if (this.type == TYPE.OK) { + return true; + } + return false; + } + + public TYPE getType() { + return type; + } + private TYPE type; + + public String getValue() { + return value; + } + + public String getReason() { + return reason; + } + private String value; private String reason; diff --git a/common/src/main/java/org/hyperskill/database/common/Util.java b/common/src/main/java/org/hyperskill/database/common/Util.java new file mode 100644 index 0000000..17c20f5 --- /dev/null +++ b/common/src/main/java/org/hyperskill/database/common/Util.java @@ -0,0 +1,58 @@ +package org.hyperskill.database.common; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +public class Util { + public static Request read(String filename) throws IOException, IllegalArgumentException { + Path file = Paths.get(filename); + String command = null; + String key = null; + StringBuilder value = new StringBuilder(); + try (InputStream in = Files.newInputStream(file); + BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { + String line = null; + int lineProcessing = 0; + while ((line = reader.readLine()) != null) { + switch (lineProcessing) { + case 0: + command = line; + lineProcessing++; + break; + case 1: + key = line; + lineProcessing++; + break; + case 2: + value.append(line); + lineProcessing++; + break; + default: + value.append(" "); + value.append(line); + lineProcessing++; + break; + } + } + } + return new Request(command, key, value.toString()); + } + + public static void write(Response response, String outFileName) { + Objects.requireNonNull(response, "Response can't be null in Util.write"); + Objects.requireNonNull(outFileName, "outFileName can't be null in Util.write"); + try (FileWriter fw = new FileWriter(outFileName, false); + BufferedWriter bw = new BufferedWriter(fw); + PrintWriter out = new PrintWriter(bw)) { + out.println(response.getType()); + out.println(response.getValue()); + + } catch (IOException e) { + System.out.println(e.toString()); + } + } +} diff --git a/server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java b/server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java index 2315b40..50281f8 100644 --- a/server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java +++ b/server/src/main/java/org/hyperskill/database/serverside/JsonProtocol.java @@ -7,35 +7,5 @@ import java.util.Objects; public class JsonProtocol { - JsonStorage storage = new JsonStorage(); - public Response processInput(Request input) { - Objects.requireNonNull(input, "Request cannot be empty in JsonProtocol.processInput"); - Response response; - switch (input.getType()) { - case GET: - JsonElement result = storage.get(input.getKey()); - if (result != null) { - response = new Response("ok", result.toString(), null); - } else { - response = new Response("fail", null, "No such key"); - } - break; - case SET: - storage.set(input.getKey(), input.getValue()); - response = new Response("Ok", null, null); - break; - case DELETE: - if (storage.get(input.getKey()) != null) { - storage.delete(input.getKey()); - response = new Response("ok", null, null); - } else { - response = new Response("fail", null, "No such key"); - } - break; - default: - throw new IllegalArgumentException(input.getType().toString() + " is not allowed command"); - } - return response; - } } diff --git a/server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java b/server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java index d0c935d..2b73668 100644 --- a/server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java +++ b/server/src/main/java/org/hyperskill/database/serverside/JsonStorage.java @@ -1,22 +1,81 @@ package org.hyperskill.database.serverside; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.google.gson.*; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; public class JsonStorage { + private static final String FILENAME = "data.json"; + + private static JsonObject storage; + private static ReadWriteLock lock; + private static Lock readLock; + private static Lock writeLock; - private JsonObject storage = new JsonObject(); + private static final JsonStorage INSTANCE = new JsonStorage(); - public void set(String property, String value) { + private JsonStorage() { + storage = new JsonObject(); + readData(); + lock = new ReentrantReadWriteLock(); + readLock = lock.readLock(); + writeLock = lock.writeLock(); + } + + public static JsonStorage getINSTANCE() { + return INSTANCE; + } + + public static void set(String property, String value) { + writeLock.lock(); storage.addProperty(property, value); + commit(); + writeLock.unlock(); } - public JsonElement get(String name) { - return storage.get(name); + public static JsonElement get(String name) { + readLock.lock(); + JsonElement element = storage.get(name); + readLock.unlock(); + return element; } - public void delete(String name) { + public static void delete(String name) { + writeLock.lock(); storage.remove(name); + commit(); + writeLock.unlock(); + } + + private static void commit() { + try (FileOutputStream fos = new FileOutputStream(FILENAME); + OutputStreamWriter isr = new OutputStreamWriter(fos, + StandardCharsets.UTF_8)) { + Gson gson = new Gson(); + gson.toJson(storage, isr); + } catch (Exception ioe) { + System.out.println("save db except"); + ioe.printStackTrace(); + } } + private static void readData() { + Gson gson = new GsonBuilder().create(); + Path path = new File(FILENAME).toPath(); + try { + JsonParser parser = new JsonParser(); + Object object = parser.parse(new FileReader(FILENAME)); + storage = (JsonObject) object; + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/server/src/main/java/org/hyperskill/database/serverside/NetworkService.java b/server/src/main/java/org/hyperskill/database/serverside/NetworkService.java new file mode 100644 index 0000000..46ff13e --- /dev/null +++ b/server/src/main/java/org/hyperskill/database/serverside/NetworkService.java @@ -0,0 +1,96 @@ +package org.hyperskill.database.serverside; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import org.hyperskill.database.common.Request; +import org.hyperskill.database.common.Response; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +class NetworkService implements Runnable { + private final ServerSocket serverSocket; + private final ExecutorService pool; + JsonStorage storage; + + + public NetworkService(int port, int poolSize) + throws IOException { + serverSocket = new ServerSocket(port); + pool = Executors.newFixedThreadPool(poolSize); + storage = JsonStorage.getINSTANCE(); + } + + public void run() { // run the service + try { + for (; ; ) { + pool.execute(new Handler(serverSocket.accept(), storage)); + } + } catch (IOException ex) { + pool.shutdown(); + } + } +} + +class Handler implements Runnable { + private final Socket socket; + private JsonStorage storage; + + Handler(Socket socket, JsonStorage storage) { + this.socket = socket; + this.storage = storage; + } + + private static Response processInput(JsonStorage storage, Request input) { + Objects.requireNonNull(input, "Request cannot be empty in JsonProtocol.processInput"); + Response response; + switch (input.getType()) { + case GET: + JsonElement result = storage.get(input.getKey()); + if (result != null) { + response = new Response("ok", result.toString(), null); + } else { + response = new Response("fail", null, "No such key"); + } + break; + case SET: + storage.set(input.getKey(), input.getValue()); + response = new Response("Ok", null, null); + break; + case DELETE: + if (storage.get(input.getKey()) != null) { + storage.delete(input.getKey()); + response = new Response("ok", null, null); + } else { + response = new Response("fail", null, "No such key"); + } + break; + default: + throw new IllegalArgumentException(input.getType().toString() + " is not allowed command"); + } + return response; + } + + public void run() { + try ( + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()) + ) { + String inputLine, outputLine; + inputLine = input.readUTF(); // reading a message + Gson gson = new Gson(); + Request request = gson.fromJson(inputLine, Request.class); + Response response = processInput(storage, request); + String out = gson.toJson(response); + output.writeUTF(out); // resend it to the client + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/server/src/main/java/org/hyperskill/database/serverside/Server.java b/server/src/main/java/org/hyperskill/database/serverside/Server.java index ed2c6ac..8ba1b9d 100644 --- a/server/src/main/java/org/hyperskill/database/serverside/Server.java +++ b/server/src/main/java/org/hyperskill/database/serverside/Server.java @@ -1,14 +1,6 @@ package org.hyperskill.database.serverside; -import com.google.gson.Gson; -import org.hyperskill.database.common.Request; -import org.hyperskill.database.common.Response; - -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; public class Server { public static void main(String[] args) { @@ -18,7 +10,14 @@ public static void main(String[] args) { } int portNumber = Integer.parseInt(args[0]); - JsonProtocol protocol = new JsonProtocol(); + try { + NetworkService nws = new NetworkService(portNumber, 10); + nws.run(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } +/* + try (ServerSocket server = new ServerSocket(portNumber)) { while (true) { try ( @@ -26,11 +25,11 @@ public static void main(String[] args) { DataInputStream input = new DataInputStream(socket.getInputStream()); DataOutputStream output = new DataOutputStream(socket.getOutputStream()) ) { - String inputLine, outputLine; + String inputLine; inputLine = input.readUTF(); // reading a message Gson gson = new Gson(); Request request = gson.fromJson(inputLine, Request.class); - Response response = protocol.processInput(request); + Response response = processInput(storage, request); String out = gson.toJson(response); output.writeUTF(out); // resend it to the client } @@ -38,5 +37,37 @@ public static void main(String[] args) { } catch (IOException e) { e.printStackTrace(); } + */ + } +/* + private static Response processInput(JsonStorage storage, Request input) { + Objects.requireNonNull(input, "Request cannot be empty in JsonProtocol.processInput"); + Response response; + switch (input.getType()) { + case GET: + JsonElement result = storage.get(input.getKey()); + if (result != null) { + response = new Response("ok", result.toString(), null); + } else { + response = new Response("fail", null, "No such key"); + } + break; + case SET: + storage.set(input.getKey(), input.getValue()); + response = new Response("Ok", null, null); + break; + case DELETE: + if (storage.get(input.getKey()) != null) { + storage.delete(input.getKey()); + response = new Response("ok", null, null); + } else { + response = new Response("fail", null, "No such key"); + } + break; + default: + throw new IllegalArgumentException(input.getType().toString() + " is not allowed command"); + } + return response; } + */ }