diff --git a/Lab.Client/src/main/java/me/zinch/Lab6/Client/client/Client.java b/Lab.Client/src/main/java/me/zinch/Lab6/Client/client/Client.java index 9adc491..6a1e4b4 100644 --- a/Lab.Client/src/main/java/me/zinch/Lab6/Client/client/Client.java +++ b/Lab.Client/src/main/java/me/zinch/Lab6/Client/client/Client.java @@ -26,23 +26,16 @@ public class Client { if (sendMessage(new BodylessMessage(MessageType.HELLO)).getType() == MessageType.HELLO) { Console.log(String.format("Соединение с сервером %s:%s установлено", address, port)); } - } catch (IOException e) { - throw new ConnectionErrorException(); - } catch (ClassNotFoundException e) { + } catch (IOException | ClassNotFoundException e) { throw new ResponseException(); } } - public Message sendMessage(Message message) throws IOException, ClassNotFoundException { + public Message sendMessage(Message message) throws ClassNotFoundException, IOException { try (var socket = new Socket(address, port); var bufferedSocketOutputStream = new BufferedOutputStream(socket.getOutputStream()); var byteArrayOutputStream = new ByteArrayOutputStream(); var objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { - int connectionTries = 0; - while(!socket.isConnected()) { - if (connectionTries++ > 5) throw new IOException(); - Thread.sleep(10 + (long) connectionTries * connectionTries*100); - } objectOutputStream.writeObject(message); objectOutputStream.flush(); @@ -52,8 +45,8 @@ public class Client { try (var objectInputStream = new ObjectInputStream(socket.getInputStream())) { return (Message) objectInputStream.readObject(); } - } catch (InterruptedException e) { - throw new RuntimeException(e); + } catch (IOException e) { + throw new IOException("Сервер не доступен"); } } } diff --git a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Add.java b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Add.java index 60e8f30..89d02e1 100644 --- a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Add.java +++ b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Add.java @@ -26,7 +26,8 @@ public class Add extends Command { public String action(Client client) throws CommandActionException { try { var productDTO = Console.readProductDTO(); - var response = (BodylessMessage) client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), productDTO)); + var request = new BodyfulMessage(MessageType.POST, Console.getLastCommand(), productDTO); + var response = (BodylessMessage) client.sendMessage(request); return response.getBody().toString(); } catch (IOException | ClassNotFoundException e) { throw new CommandActionException(e); diff --git a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/IsIdExists.java b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/IsIdExists.java index fe08961..04a81fc 100644 --- a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/IsIdExists.java +++ b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/IsIdExists.java @@ -20,7 +20,7 @@ public class IsIdExists extends Command { try { Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]); var response = (BodylessMessage) client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), id)); - if (response.getType() == MessageType.ERROR) throw new CommandActionException(); + if (response.getType() == MessageType.ERROR) throw new CommandActionException(response.getBody().toString()); return response.getBody().toString(); } catch (IOException | ClassNotFoundException e) { throw new CommandActionException(e); diff --git a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Save.java b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Save.java index 7c5a97a..95c0cf8 100644 --- a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Save.java +++ b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Save.java @@ -11,6 +11,6 @@ import java.io.IOException; */ public class Save extends Command { public Save() { - super("save", "сохранить коллекцию в файл"); + super("save", "save the collection to a file"); } } diff --git a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Update.java b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Update.java index cb21d98..545681b 100644 --- a/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Update.java +++ b/Lab.Client/src/main/java/me/zinch/Lab6/Client/commands/Update.java @@ -7,11 +7,6 @@ import me.zinch.Lab6.Domain.dto.BodyfulMessage; import me.zinch.Lab6.Domain.dto.BodylessMessage; import me.zinch.Lab6.Domain.dto.MessageBody; import me.zinch.Lab6.Domain.dto.MessageType; -import me.zinch.Lab6.Domain.dto.UpdateBody; -import me.zinch.Lab6.Domain.exceptions.ValidationException; -import me.zinch.Lab6.Domain.models.ProductDTO; -import me.zinch.Lab6.Domain.validator.Validators; -import me.zinch.Lab6.Domain.wrapper.IStorage; import java.io.IOException; import java.util.regex.Pattern; @@ -27,18 +22,26 @@ public class Update extends Command { @Override public String action(Client client) throws CommandActionException { try { - Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]); + var command = Console.getLastCommand(); + Long id = Long.parseLong(command.split(" ")[1]); var isIdExists = new IsIdExists(); - Console.appendHistory(String.format("%s %s", isIdExists.getName(), id)); + Console.appendHistory(String.format("%s %s", isIdExists.getSignature(), id)); isIdExists.action(client); + var getProductById = new GetProductById(); + Console.appendHistory(String.format("%s %s", getProductById.getSignature(), id)); + var product = getProductById.action(client); + + Console.log("Вы собираетесь обновить следующий продукт"); + Console.log(product); + var productDTO = Console.readProductDTO(); var response = (BodylessMessage) client.sendMessage( - new BodyfulMessage(MessageType.POST, this.getSignature(), - new MessageBody(String.format("%s %s", this.getSignature(), id), productDTO))); + new BodyfulMessage(MessageType.POST, command, + new MessageBody(String.format("%s %s", command, id), productDTO))); return response.getBody().toString(); - } catch (IOException | ClassNotFoundException e) { + } catch (IOException | ClassNotFoundException | NumberFormatException e) { throw new CommandActionException(e); } } diff --git a/Lab.Client/src/main/java/me/zinch/Lab6/Client/console/Console.java b/Lab.Client/src/main/java/me/zinch/Lab6/Client/console/Console.java index dc22f69..e535f4b 100644 --- a/Lab.Client/src/main/java/me/zinch/Lab6/Client/console/Console.java +++ b/Lab.Client/src/main/java/me/zinch/Lab6/Client/console/Console.java @@ -171,13 +171,14 @@ public class Console { public static void run() { while (client == null) { - var address = readField("Хост"); - int port = Integer.parseInt(readField("Порт")); try { + var address = readField("Хост"); + int port = Integer.parseInt(readField("Порт")); client = new Client(address, port); + } catch (NumberFormatException e) { + log("Порт должен быть числом от 1 до 65535"); } catch (ResponseException | ConnectionErrorException e) { - log(e.getMessage()); - log("Попробуйте ещё раз"); + log("Ошибка при подключении\nПопробуйте ещё раз"); } } diff --git a/Lab.Server/pom.xml b/Lab.Server/pom.xml index 990b32f..1cd1302 100644 --- a/Lab.Server/pom.xml +++ b/Lab.Server/pom.xml @@ -57,6 +57,17 @@ 1.0-SNAPSHOT compile + + com.fasterxml.jackson.core + jackson-annotations + 2.17.1 + compile + + + org.jline + jline + 3.26.1 + diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/App.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/App.java index 7f8b8a7..af636c0 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/App.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/App.java @@ -1,6 +1,9 @@ package me.zinch.Lab6.Server; import me.zinch.Lab6.Server.console.Console; +import me.zinch.Lab6.Server.console.ShutdownHook; +import me.zinch.Lab6.Server.files.DbController; +import me.zinch.Lab6.Server.wrapper.ProductCollection; import java.io.IOException; diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/Server.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/Server.java index 9a37ace..e8afff8 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/Server.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/Server.java @@ -8,6 +8,8 @@ import me.zinch.Lab6.Domain.wrapper.IStorage; import me.zinch.Lab6.Server.commands.CommandManager; import me.zinch.Lab6.Server.commands.GetCommand; import me.zinch.Lab6.Server.commands.PostCommand; +import me.zinch.Lab6.Server.exceptions.CommandActionException; +import me.zinch.Lab6.Server.files.DbController; import me.zinch.Lab6.Server.wrapper.ProductCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +28,7 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.text.Normalizer; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -53,10 +56,15 @@ public class Server { } public void run() throws IOException { + run(() -> {}); + } + + public void run(Runnable middleware) throws IOException { log.info("The server is running"); while (isRunning) { selector.select(this::handleKey); + middleware.run(); } } @@ -134,8 +142,12 @@ public class Server { log.error("Command {} not found", inputCommand); return serialize(new BodylessMessage(MessageType.ERROR, String.format("Command %s not found", inputCommand))); } - var action = (GetCommand) command.get(); - return serialize(new BodylessMessage(MessageType.OK, action.action(storage))); + try { + var action = (GetCommand) command.get(); + return serialize(new BodylessMessage(MessageType.OK, action.action(storage))); + } catch (CommandActionException e) { + return serialize(new BodylessMessage(MessageType.ERROR, e.getMessage())); + } } private ByteBuffer handlePostCommand(MessageBody request) throws IOException { @@ -148,8 +160,12 @@ public class Server { return serialize(new BodylessMessage(MessageType.ERROR, String.format("Command %s not found", inputCommand))); } - var action = (PostCommand) command.get(); - return serialize(new BodylessMessage(MessageType.OK, action.action(storage, body))); + try { + var action = (PostCommand) command.get(); + return serialize(new BodylessMessage(MessageType.OK, action.action(storage, body))); + } catch (CommandActionException e) { + return serialize(new BodylessMessage(MessageType.ERROR, e.getMessage())); + } } public static ByteBuffer serialize(Serializable obj) throws IOException { @@ -165,5 +181,6 @@ public class Server { isRunning = false; serverSocketChannel.close(); selector.close(); + DbController.saveDb(storage.toList()); } } diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/CommandManager.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/CommandManager.java index 6bdd111..3f540ad 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/CommandManager.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/CommandManager.java @@ -41,6 +41,7 @@ public class CommandManager { registerCommand(new AddIfMin()); registerCommand(new RemoveLower()); registerCommand(new Save()); + registerCommand(new GetProduct()); registerCommand(new Help()); } diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Exit.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Exit.java index 6d0c677..2683839 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Exit.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Exit.java @@ -8,7 +8,7 @@ import me.zinch.Lab6.Server.console.Console; */ public class Exit extends GetCommand { public Exit() { - super("exit", "завершить программу (без сохранения в файл)"); + super("exit", "terminate the program (without saving to a file)"); } @Override diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/GetProduct.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/GetProduct.java new file mode 100644 index 0000000..221573d --- /dev/null +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/GetProduct.java @@ -0,0 +1,18 @@ +package me.zinch.Lab6.Server.commands; + +import me.zinch.Lab6.Domain.wrapper.IStorage; +import me.zinch.Lab6.Server.exceptions.CommandActionException; + +import java.util.regex.Pattern; + +public class GetProduct extends PostCommand { + public GetProduct() { + super("get_product_by_id", "", Pattern.compile("^get_product_by_id +.")); + } + + @Override + public String action(IStorage productCollection, Object obj) throws CommandActionException { + if (!productCollection.isProductIdExists((Long) obj)) throw new CommandActionException("Продукт с таким ID не существует"); + return productCollection.getProductById((Long) obj).toString(); + } +} diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Help.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Help.java index 04bfec3..ffcb379 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Help.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/Help.java @@ -7,11 +7,11 @@ import me.zinch.Lab6.Domain.wrapper.IStorage; */ public class Help extends GetCommand { public Help() { - super("help", "вывести справку по доступным командам"); + super("help", "display help for available commands"); } @Override public String action(IStorage productCollection) { - return CommandManager.getRegisteredCommand(); + return SystemCommandManager.getRegisteredCommand(); } } diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/IsIdExists.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/IsIdExists.java index 99ec334..12fbb75 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/IsIdExists.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/commands/IsIdExists.java @@ -12,7 +12,7 @@ public class IsIdExists extends PostCommand { @Override public String action(IStorage productCollection, Object obj) throws CommandActionException { - if (!productCollection.isProductIdExists((Long) obj)) throw new CommandActionException(); - return null; + if (!productCollection.isProductIdExists((Long) obj)) throw new CommandActionException("Продукт с таким ID не существует"); + return "Exists"; } } diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/Console.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/Console.java index 5a6c80d..96edce8 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/Console.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/Console.java @@ -1,12 +1,15 @@ package me.zinch.Lab6.Server.console; import me.zinch.Lab6.Domain.exceptions.ValidationException; +import me.zinch.Lab6.Domain.wrapper.IStorage; import me.zinch.Lab6.Server.ServerBuilder; import me.zinch.Lab6.Server.commands.GetCommand; import me.zinch.Lab6.Server.commands.SystemCommandManager; import me.zinch.Lab6.Server.exceptions.CommandActionException; import me.zinch.Lab6.Server.files.DbController; import me.zinch.Lab6.Server.wrapper.ProductCollection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.NoSuchElementException; @@ -18,67 +21,66 @@ import java.util.Scanner; */ public class Console { private static final Scanner scanner = new Scanner(System.in); + private static final Logger log = LoggerFactory.getLogger(Console.class); private static boolean isRunning = true; private static boolean isExitMessageShowed = false; - - public static void log(String msg) { - if (isRunning) System.out.println(msg); - } - - public static void log() { - log(""); - } + private static IStorage collection; public static void stopApp() { showExitMessage(); isRunning = false; + System.exit(0); } public static void showExitMessage() { - if (!isExitMessageShowed) log("\nВсего хорошего!"); + if (!isExitMessageShowed) log.info("Have a nice day!"); isExitMessageShowed = true; } - private static String readString() { - if (!scanner.hasNextLine()) Console.stopApp(); - var input = scanner.nextLine().trim(); - return input.isEmpty() ? null : input; - } - public static void run() throws IOException, ValidationException { - var collection = new ProductCollection(DbController.loadDb()); + collection = new ProductCollection(DbController.loadDb()); var server = new ServerBuilder() .setPort(3000) .setCollection(collection) .build(); + + Console.handleInput(); + server.run(); - log("Добро пожаловать! Для просмотра команд введите help"); - - while(isRunning) { - System.out.print(":"); - + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + Console.stopApp(); try { - var input = scanner.nextLine().trim(); - var command = SystemCommandManager.getCommandByInput(input); - - if (command.isPresent()) { - var action = (GetCommand) command.get(); - try { - log(action.action(null)); - } catch (CommandActionException e) { - log(e.getMessage()); - } - } else { - log("Такой команды не существует. Напишите help, чтобы посмотреть список доступных команд."); - } - } catch (NoSuchElementException e) { - stopApp(); + server.stop(); + } catch (IOException e) { + throw new RuntimeException(e); } - log(); - } - scanner.close(); - server.stop(); + })); + } + + public static void handleInput() { + new Thread(() -> { + while(isRunning) { + try { + var input = scanner.nextLine().trim(); + var command = SystemCommandManager.getCommandByInput(input); + + if (command.isPresent()) { + var action = (GetCommand) command.get(); + try { + log.info(action.action(collection)); + } catch (CommandActionException e) { + log.info(e.getMessage()); + } + } else { + log.info("This command does not exist. Write help to see a list of available commands."); + } + } catch (NoSuchElementException e) { + stopApp(); + } + } + scanner.close(); + }).start(); } } diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/ShutdownHook.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/ShutdownHook.java index 15e61cd..2439529 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/ShutdownHook.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/console/ShutdownHook.java @@ -5,6 +5,6 @@ package me.zinch.Lab6.Server.console; */ public class ShutdownHook extends Thread { public ShutdownHook() { - super(new Thread(Console::stopApp)); + super(); } } diff --git a/Lab.Server/src/main/java/me/zinch/Lab6/Server/files/DbController.java b/Lab.Server/src/main/java/me/zinch/Lab6/Server/files/DbController.java index 721ebfe..32112a3 100644 --- a/Lab.Server/src/main/java/me/zinch/Lab6/Server/files/DbController.java +++ b/Lab.Server/src/main/java/me/zinch/Lab6/Server/files/DbController.java @@ -48,7 +48,7 @@ public class DbController { } } - public static List loadDb() throws IOException { + public static List loadDb() { try { BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path)); List collection = xmlMapper.readValue(bufferedInputStream, Products.class).getProducts(); diff --git a/db.xml b/db.xml index b41fb6f..449f999 100644 --- a/db.xml +++ b/db.xml @@ -1 +1 @@ -1Product 1100501709294400.00000000050PN12330KILOGRAMSJohn DoeAB12345BLACK10.520Home2Product 22001001709294700.00000000080PN45660CENTIMETERSAlice SmithCD67890BLUE20.830Office3Product 3150-2001709295000.00000000012090GRAMSEmma JohnsonEF24680GREEN30.240Warehouse4Product 4300-3001709295300.000000000200PN789150KILOGRAMSBob BrownGH13579ORANGE40.650Factory5Product 54004001709295600.000000000150PN246100CENTIMETERSGrace LeeIJ35791WHITE50.960Store611111716766945.58466260011231CENTIMETERS1313412BLACK1.011 \ No newline at end of file +611111716766945.58466260011231CENTIMETERS1313412BLACK1.0111Product 1100501709294400.00000000050PN12330KILOGRAMSJohn DoeAB12345BLACK10.520Home2Product 22001001709294700.00000000080PN45660CENTIMETERSAlice SmithCD67890BLUE20.830Office3Product 3150-2001709295000.00000000012090GRAMSEmma JohnsonEF24680GREEN30.240Warehouse4Product 4300-3001709295300.000000000200PN789150KILOGRAMSBob BrownGH13579ORANGE40.650Factory5Product 54004001709295600.000000000150PN246100CENTIMETERSGrace LeeIJ35791WHITE50.960Store \ No newline at end of file