Добавлена обработка инпута на сервере

This commit is contained in:
Ivan Zinchenko 2024-05-29 18:59:45 +03:00
parent db490ed5ec
commit 5b95fff14d
Signed by: zinch
GPG Key ID: 6D45AA2C8FD6A37E
18 changed files with 130 additions and 80 deletions

View File

@ -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("Сервер не доступен");
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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("Ошибка при подключении\опробуйте ещё раз");
}
}

View File

@ -57,6 +57,17 @@
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.17.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline</artifactId>
<version>3.26.1</version>
</dependency>
</dependencies>
<build>

View File

@ -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;

View File

@ -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());
}
}

View File

@ -41,6 +41,7 @@ public class CommandManager {
registerCommand(new AddIfMin());
registerCommand(new RemoveLower());
registerCommand(new Save());
registerCommand(new GetProduct());
registerCommand(new Help());
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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";
}
}

View File

@ -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();
}
}

View File

@ -5,6 +5,6 @@ package me.zinch.Lab6.Server.console;
*/
public class ShutdownHook extends Thread {
public ShutdownHook() {
super(new Thread(Console::stopApp));
super();
}
}

View File

@ -48,7 +48,7 @@ public class DbController {
}
}
public static List<Product> loadDb() throws IOException {
public static List<Product> loadDb() {
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));
List<Product> collection = xmlMapper.readValue(bufferedInputStream, Products.class).getProducts();

2
db.xml
View File

@ -1 +1 @@
<Products><Product><id>1</id><name>Product 1</name><coordinates><x>100</x><y>50</y></coordinates><creationDate>1709294400.000000000</creationDate><price>50</price><partNumber>PN123</partNumber><manufactureCost>30</manufactureCost><unitOfMeasure>KILOGRAMS</unitOfMeasure><owner><name>John Doe</name><passportID>AB12345</passportID><hairColor>BLACK</hairColor><location><x>10.5</x><y>20</y><name>Home</name></location></owner></Product><Product><id>2</id><name>Product 2</name><coordinates><x>200</x><y>100</y></coordinates><creationDate>1709294700.000000000</creationDate><price>80</price><partNumber>PN456</partNumber><manufactureCost>60</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>Alice Smith</name><passportID>CD67890</passportID><hairColor>BLUE</hairColor><location><x>20.8</x><y>30</y><name>Office</name></location></owner></Product><Product><id>3</id><name>Product 3</name><coordinates><x>150</x><y>-200</y></coordinates><creationDate>1709295000.000000000</creationDate><price>120</price><manufactureCost>90</manufactureCost><unitOfMeasure>GRAMS</unitOfMeasure><owner><name>Emma Johnson</name><passportID>EF24680</passportID><hairColor>GREEN</hairColor><location><x>30.2</x><y>40</y><name>Warehouse</name></location></owner></Product><Product><id>4</id><name>Product 4</name><coordinates><x>300</x><y>-300</y></coordinates><creationDate>1709295300.000000000</creationDate><price>200</price><partNumber>PN789</partNumber><manufactureCost>150</manufactureCost><unitOfMeasure>KILOGRAMS</unitOfMeasure><owner><name>Bob Brown</name><passportID>GH13579</passportID><hairColor>ORANGE</hairColor><location><x>40.6</x><y>50</y><name>Factory</name></location></owner></Product><Product><id>5</id><name>Product 5</name><coordinates><x>400</x><y>400</y></coordinates><creationDate>1709295600.000000000</creationDate><price>150</price><partNumber>PN246</partNumber><manufactureCost>100</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>Grace Lee</name><passportID>IJ35791</passportID><hairColor>WHITE</hairColor><location><x>50.9</x><y>60</y><name>Store</name></location></owner></Product><Product><id>6</id><name>1</name><coordinates><x>1</x><y>11</y></coordinates><creationDate>1716766945.584662600</creationDate><price>1</price><partNumber>1</partNumber><manufactureCost>231</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>1</name><passportID>313412</passportID><hairColor>BLACK</hairColor><location><x>1.0</x><y>1</y><name>1</name></location></owner></Product></Products>
<Products><Product><id>6</id><name>1</name><coordinates><x>1</x><y>11</y></coordinates><creationDate>1716766945.584662600</creationDate><price>1</price><partNumber>1</partNumber><manufactureCost>231</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>1</name><passportID>313412</passportID><hairColor>BLACK</hairColor><location><x>1.0</x><y>1</y><name>1</name></location></owner></Product><Product><id>1</id><name>Product 1</name><coordinates><x>100</x><y>50</y></coordinates><creationDate>1709294400.000000000</creationDate><price>50</price><partNumber>PN123</partNumber><manufactureCost>30</manufactureCost><unitOfMeasure>KILOGRAMS</unitOfMeasure><owner><name>John Doe</name><passportID>AB12345</passportID><hairColor>BLACK</hairColor><location><x>10.5</x><y>20</y><name>Home</name></location></owner></Product><Product><id>2</id><name>Product 2</name><coordinates><x>200</x><y>100</y></coordinates><creationDate>1709294700.000000000</creationDate><price>80</price><partNumber>PN456</partNumber><manufactureCost>60</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>Alice Smith</name><passportID>CD67890</passportID><hairColor>BLUE</hairColor><location><x>20.8</x><y>30</y><name>Office</name></location></owner></Product><Product><id>3</id><name>Product 3</name><coordinates><x>150</x><y>-200</y></coordinates><creationDate>1709295000.000000000</creationDate><price>120</price><manufactureCost>90</manufactureCost><unitOfMeasure>GRAMS</unitOfMeasure><owner><name>Emma Johnson</name><passportID>EF24680</passportID><hairColor>GREEN</hairColor><location><x>30.2</x><y>40</y><name>Warehouse</name></location></owner></Product><Product><id>4</id><name>Product 4</name><coordinates><x>300</x><y>-300</y></coordinates><creationDate>1709295300.000000000</creationDate><price>200</price><partNumber>PN789</partNumber><manufactureCost>150</manufactureCost><unitOfMeasure>KILOGRAMS</unitOfMeasure><owner><name>Bob Brown</name><passportID>GH13579</passportID><hairColor>ORANGE</hairColor><location><x>40.6</x><y>50</y><name>Factory</name></location></owner></Product><Product><id>5</id><name>Product 5</name><coordinates><x>400</x><y>400</y></coordinates><creationDate>1709295600.000000000</creationDate><price>150</price><partNumber>PN246</partNumber><manufactureCost>100</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>Grace Lee</name><passportID>IJ35791</passportID><hairColor>WHITE</hairColor><location><x>50.9</x><y>60</y><name>Store</name></location></owner></Product></Products>