Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bff0acdd2 |
@ -1,85 +0,0 @@
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>me.zinch</groupId>
|
||||
<artifactId>Lab6-Client</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Lab6-Client</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>8.0.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>jakarta.el</artifactId>
|
||||
<version>5.0.0-M1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.23.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.zinch</groupId>
|
||||
<artifactId>Lab6-Domain</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<version>3.7.1</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>me.zinch.Lab6.Client.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.6.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -1,14 +0,0 @@
|
||||
package me.zinch.Lab6.Client;
|
||||
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.console.ShutdownHook;
|
||||
|
||||
/**
|
||||
* Main class for running the application.
|
||||
*/
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
||||
Console.run();
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
package me.zinch.Lab6.Client.client;
|
||||
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.ConnectionErrorException;
|
||||
import me.zinch.Lab6.Client.exceptions.ResponseException;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.Message;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
public class Client {
|
||||
private final String address;
|
||||
private final int port;
|
||||
|
||||
public Client(String address, int port) throws ConnectionErrorException, ResponseException {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
|
||||
try {
|
||||
if (sendMessage(new BodylessMessage(MessageType.HELLO)).getType() == MessageType.HELLO) {
|
||||
Console.log(String.format("Соединение с сервером %s:%s установлено", address, port));
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new ResponseException();
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
objectOutputStream.writeObject(message);
|
||||
objectOutputStream.flush();
|
||||
bufferedSocketOutputStream.write(byteArrayOutputStream.toByteArray());
|
||||
bufferedSocketOutputStream.flush();
|
||||
|
||||
try (var objectInputStream = new ObjectInputStream(socket.getInputStream())) {
|
||||
return (Message) objectInputStream.readObject();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Сервер не доступен");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The Add class represents a command to add a new element to a collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class Add extends Command {
|
||||
public Add() {
|
||||
super("add {element}", "добавить новый элемент в коллекцию", Pattern.compile("^add"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
try {
|
||||
var productDTO = Console.readProductDTO();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The AddIfMax class represents a command to add a new element to a collection if its price value exceeds the maximum price value in the collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class AddIfMax extends Command {
|
||||
public AddIfMax() {
|
||||
super("add_if_max {element}", "добавить новый элемент в коллекцию, если его значение цены превышает значение наибольшей цены этой коллекции", Pattern.compile("^add_if_max"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
try {
|
||||
var productDTO = Console.readProductDTO();
|
||||
var response = (BodylessMessage) client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), productDTO));
|
||||
return response.getBody().toString();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The AddIfMin class represents a command to add a new element to a collection if its price is lower than the lowest price in the collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class AddIfMin extends Command {
|
||||
public AddIfMin() {
|
||||
super("add_if_min {element}", "добавить новый элемент в коллекцию, если его значение цены меньше, чем у наименьшей цены этой коллекции", Pattern.compile("^add_if_min"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
try {
|
||||
var productDTO = Console.readProductDTO();
|
||||
var response = (BodylessMessage) client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), productDTO));
|
||||
return response.getBody().toString();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
/**
|
||||
* The Clear class represents a command to clear a collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class Clear extends Command {
|
||||
public Clear() {
|
||||
super("clear", "очистить коллекцию");
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents a command that can be executed.
|
||||
*/
|
||||
public abstract class Command {
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final Pattern pattern;
|
||||
|
||||
public Command(String name, String description, Pattern pattern) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public Command(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.pattern = Pattern.compile("^" + name);
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public final String getSignature() {
|
||||
return name.split(" ")[0];
|
||||
}
|
||||
|
||||
public final String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public final Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public final boolean checkPattern(String input) {
|
||||
return pattern.matcher(input).matches();
|
||||
}
|
||||
|
||||
public String action(Client client) throws CommandActionException {
|
||||
try {
|
||||
var response = (BodylessMessage) client.sendMessage(new BodylessMessage(MessageType.GET, this.getName()));
|
||||
return response.getBody().toString();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to filter elements whose 'name' field contains the specified substring.
|
||||
*/
|
||||
public class FilterContainsName extends Command {
|
||||
public FilterContainsName() {
|
||||
super("filter_contains_name name", "вывести элементы, значение поля name которых содержит заданную подстроку", Pattern.compile("^filter_contains_name \\w+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
try {
|
||||
String name = Console.getLastCommand().split(" ")[1];
|
||||
var response = (BodylessMessage) client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), name));
|
||||
return response.getBody().toString();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class GetProductById extends Command {
|
||||
public GetProductById() {
|
||||
super("get_product_by_id {element}", "", Pattern.compile("^get_product_by_id +."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
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(response.getBody().toString());
|
||||
return response.getBody().toString();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
/**
|
||||
* A command to display information about the collection (type, initialization date, number of elements, etc.) to the standard output stream.
|
||||
*/
|
||||
public class Info extends Command {
|
||||
public Info() {
|
||||
super("info", "вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.)");
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class IsIdExists extends Command {
|
||||
public IsIdExists() {
|
||||
super("is_id_exists {element}", "", Pattern.compile("^is_id_exists +."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
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(response.getBody().toString());
|
||||
return response.getBody().toString();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to remove an element from the collection by its id.
|
||||
*/
|
||||
public class Remove extends Command {
|
||||
public Remove() {
|
||||
super("remove_by_id id", "удалить элемент из коллекции по его id", Pattern.compile("^remove_by_id .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
try {
|
||||
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
|
||||
var response = (BodylessMessage) client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), id));
|
||||
return response.getBody().toString();
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Domain.dto.BodyfulMessage;
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to remove all elements from the collection that have ids lower than the specified id.
|
||||
*/
|
||||
public class RemoveLower extends Command {
|
||||
public RemoveLower() {
|
||||
super("remove_lower id", "удалить из коллекции все элементы, меньшие, чем заданный по id", Pattern.compile("^remove_lower .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
try {
|
||||
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
|
||||
var response = (BodylessMessage) client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), id));
|
||||
return response.getBody().toString();
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
/**
|
||||
* A command to save the collection to a file.
|
||||
*/
|
||||
public class Save extends Command {
|
||||
public Save() {
|
||||
super("save", "save the collection to a file");
|
||||
}
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
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 java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to update the value of an element in the collection, whose id is specified.
|
||||
*/
|
||||
public class Update extends Command {
|
||||
public Update() {
|
||||
super("update id {element}", "обновить значение элемента коллекции, id которого равен заданному", Pattern.compile("^update .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
try {
|
||||
var command = Console.getLastCommand();
|
||||
Long id = Long.parseLong(command.split(" ")[1]);
|
||||
|
||||
var isIdExists = new IsIdExists();
|
||||
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, command,
|
||||
new MessageBody(String.format("%s %s", command, id), productDTO)));
|
||||
return response.getBody().toString();
|
||||
} catch (IOException | ClassNotFoundException | NumberFormatException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,208 +0,0 @@
|
||||
package me.zinch.Lab6.Client.console;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.commands.CommandManager;
|
||||
import me.zinch.Lab6.Client.exceptions.ColorFormatException;
|
||||
import me.zinch.Lab6.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Client.exceptions.ConnectionErrorException;
|
||||
import me.zinch.Lab6.Client.exceptions.ResponseException;
|
||||
import me.zinch.Lab6.Client.exceptions.UnitOfMeasureFormatException;
|
||||
import me.zinch.Lab6.Domain.models.Color;
|
||||
import me.zinch.Lab6.Domain.models.Coordinates;
|
||||
import me.zinch.Lab6.Domain.models.Location;
|
||||
import me.zinch.Lab6.Domain.models.Person;
|
||||
import me.zinch.Lab6.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab6.Domain.models.UnitOfMeasure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Console class provides methods for interacting with the console, reading user input, and managing application flow.
|
||||
* This class includes methods for appending input history, stopping the application, reading product DTO from the console, and running the application loop.
|
||||
*/
|
||||
public class Console {
|
||||
private static final Scanner scanner = new Scanner(System.in);
|
||||
private static final List<String> history = new ArrayList<>();
|
||||
private static boolean isRunning = true;
|
||||
private static boolean isExitMessageShowed = false;
|
||||
private static Client client;
|
||||
|
||||
public static void appendHistory(String input) {
|
||||
history.add(input);
|
||||
}
|
||||
|
||||
public static void log(Object msg) {
|
||||
if (isRunning) System.out.println(msg.toString());
|
||||
}
|
||||
|
||||
public static void log() {
|
||||
log("");
|
||||
}
|
||||
|
||||
public static void stopAppWithoutSaving() {
|
||||
showExitMessage();
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
public static void stopAppWithSaving() {
|
||||
stopAppWithoutSaving();
|
||||
}
|
||||
|
||||
public static void showExitMessage() {
|
||||
if (!isExitMessageShowed) log("\nВсего хорошего!");
|
||||
isExitMessageShowed = true;
|
||||
}
|
||||
|
||||
public static String getLastCommand() {
|
||||
return history.get(history.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
private static String readString() {
|
||||
if (!scanner.hasNextLine()) Console.stopAppWithSaving();
|
||||
var input = scanner.nextLine().trim();
|
||||
return input.isEmpty() ? null : input;
|
||||
}
|
||||
|
||||
private static Long readLong() {
|
||||
var input = readString();
|
||||
if (input == null || input.isEmpty()) return null;
|
||||
try {
|
||||
return Long.parseLong(input);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new NumberFormatException(String.format("Не могу распознать %s как число", input));
|
||||
}
|
||||
}
|
||||
|
||||
private static Color readColor() throws ColorFormatException {
|
||||
System.out.format("Цвет волос(%s): ", Color.getColorsString());
|
||||
var input = readString();
|
||||
if (input == null || input.isEmpty()) return null;
|
||||
try {
|
||||
return Color.create(Integer.parseInt(input));
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
try {
|
||||
return Color.create(input);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new ColorFormatException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static UnitOfMeasure readUnitOfMeasure() throws UnitOfMeasureFormatException {
|
||||
System.out.format("Единица измерения(%s): ", UnitOfMeasure.getUnitOfMeasuerString());
|
||||
var input = readString();
|
||||
try {
|
||||
return UnitOfMeasure.create(Integer.parseInt(input));
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
try {
|
||||
return UnitOfMeasure.create(input);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new ColorFormatException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Location readLocation() throws NumberFormatException {
|
||||
System.out.print("Создать поле Location? (Y/n): ");
|
||||
var input = readString();
|
||||
if (input != null && input.equalsIgnoreCase("n")) return null;
|
||||
System.out.print("Координата x локации: ");
|
||||
var locationX = Float.parseFloat(readString());
|
||||
System.out.print("Координата y локации: ");
|
||||
var locationY = Integer.parseInt(readString());
|
||||
System.out.print("Название: ");
|
||||
var locationName = readString();
|
||||
return new Location(locationX, locationY, locationName);
|
||||
}
|
||||
|
||||
private static void setField(String fieldName, Runnable function) {
|
||||
while (isRunning) {
|
||||
if (fieldName != null) System.out.format("%s: ", fieldName);
|
||||
try {
|
||||
function.run();
|
||||
return;
|
||||
} catch (NullPointerException e) {
|
||||
log("Произошла ошибка при заполнении поля\nПоле не может быть пустым");
|
||||
} catch (Exception e) {
|
||||
System.out.format("Произошла ошибка при заполнении поля%n%s%n", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setField(Runnable function) {
|
||||
setField(null, function);
|
||||
}
|
||||
|
||||
private static String readField(String message) {
|
||||
System.out.print(message + ": ");
|
||||
return readString();
|
||||
}
|
||||
|
||||
public static ProductDTO readProductDTO() {
|
||||
var productDTO = new ProductDTO();
|
||||
var coordinates = new Coordinates();
|
||||
var owner = new Person();
|
||||
log("Заполните следующие поля: ");
|
||||
|
||||
setField("Название [не может быть пустым]", () -> productDTO.setName(readString()));
|
||||
setField("Координата x [должна быть меньше 884]", () -> coordinates.setX(readLong()));
|
||||
setField("Координата y [должна быть больше -427, не может быть пустой]", () -> coordinates.setY(readLong()));
|
||||
setField("Цена [должна быть больше 0, не может быть пустой]", () -> productDTO.setPrice(readLong()));
|
||||
setField("Номер части [не больше 82 символов, должен быть уникальным]", () -> productDTO.setPartNumber(readString()));
|
||||
setField("Себестоимость [не может быть пустым]", () -> productDTO.setManufactureCost(readLong()));
|
||||
setField(() -> productDTO.setUnitOfMeasure(readUnitOfMeasure()));
|
||||
setField("Имя владельца [не может быть пустым]", () -> owner.setName(readString()));
|
||||
setField("Данные паспорта [длина строки от 5 до 22, не может быть пустым]", () -> owner.setPassportID(readString()));
|
||||
setField(() -> owner.setHairColor(readColor()));
|
||||
setField(() -> owner.setLocation(readLocation()));
|
||||
|
||||
productDTO.setCoordinates(coordinates);
|
||||
productDTO.setOwner(owner);
|
||||
return productDTO;
|
||||
}
|
||||
|
||||
public static void run() {
|
||||
while (client == null) {
|
||||
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("Ошибка при подключении\nПопробуйте ещё раз");
|
||||
}
|
||||
}
|
||||
|
||||
log("Добро пожаловать! Для просмотра команд введите help");
|
||||
|
||||
while (isRunning) {
|
||||
System.out.print(":");
|
||||
|
||||
try {
|
||||
var input = scanner.nextLine().trim();
|
||||
var command = CommandManager.getCommandByInput(input);
|
||||
|
||||
if (command.isPresent()) {
|
||||
appendHistory(input);
|
||||
|
||||
try {
|
||||
log(command.get().action(client));
|
||||
} catch (CommandActionException e) {
|
||||
log(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
log("Такой команды не существует. Напишите help, чтобы посмотреть список доступных команд.");
|
||||
}
|
||||
} catch (NoSuchElementException e) {
|
||||
stopAppWithoutSaving();
|
||||
}
|
||||
log();
|
||||
}
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package me.zinch.Lab6.Client.console;
|
||||
|
||||
/**
|
||||
* Represents a shutdown hook that is executed when the application is stopped.
|
||||
*/
|
||||
public class ShutdownHook extends Thread {
|
||||
public ShutdownHook() {
|
||||
super(new Thread(Console::stopAppWithSaving));
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab6.Client.exceptions;
|
||||
|
||||
/**
|
||||
* Represents an exception that occurs during the execution of a command action.
|
||||
*/
|
||||
public class CommandActionException extends RuntimeException {
|
||||
public CommandActionException() {
|
||||
super("Ошибка во время выполнения команды");
|
||||
}
|
||||
|
||||
public CommandActionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CommandActionException(Throwable e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package me.zinch.Lab6.Client.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ConnectionErrorException extends IOException {
|
||||
public ConnectionErrorException() {
|
||||
super("Произошла ошибка при подключении, сервер не доступен");
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package me.zinch.Lab6.Client.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents an exception that occurs when the database initialization fails.
|
||||
*/
|
||||
public class DbInitializationException extends IOException {
|
||||
public DbInitializationException() {
|
||||
super("Ошибка! Не удалось инициализировать БД. Проверьте, что структура БД верна.");
|
||||
}
|
||||
|
||||
public DbInitializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab6.Client.exceptions;
|
||||
|
||||
/**
|
||||
* Represents an exception that occurs when an illegal product DTO is encountered during the creation or modification of a product.
|
||||
*/
|
||||
public class IllegalProductDtoException extends CommandActionException {
|
||||
public IllegalProductDtoException() {
|
||||
super("Ошибка при создании или изменении продукта. Были введены некорректные значения.");
|
||||
}
|
||||
|
||||
public IllegalProductDtoException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public IllegalProductDtoException(Throwable e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
package me.zinch.Lab6.Client.exceptions;
|
||||
|
||||
public class ResponseException extends ClassNotFoundException {
|
||||
public ResponseException() {
|
||||
super("Ошибка при обработке данных от сервера.");
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
package me.zinch.Lab6.Client.files;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* The ScriptLoader class provides methods to load scripts from files.
|
||||
*/
|
||||
public class ScriptLoader {
|
||||
public static List<String> loadList(String path) throws IOException {
|
||||
try {
|
||||
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));
|
||||
Scanner scanner = new Scanner(bufferedInputStream);
|
||||
List<String> list = new ArrayList<>();
|
||||
while (scanner.hasNextLine()) {
|
||||
list.add(scanner.nextLine());
|
||||
}
|
||||
bufferedInputStream.close();
|
||||
scanner.close();
|
||||
return list;
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new FileNotFoundException(String.format("Файл %s не найден.", path));
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Произошла неожиданная ошибка во время работы с файлом!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>me.zinch</groupId>
|
||||
<artifactId>Lab6-Domain</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>2.17.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>8.0.1.Final</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -1,10 +0,0 @@
|
||||
package me.zinch.Lab6.Domain.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class BodyfulMessage extends Message {
|
||||
public BodyfulMessage(MessageType type, String command, Serializable body) {
|
||||
this.setType(type);
|
||||
this.setBody(new MessageBody(command, body));
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package me.zinch.Lab6.Domain.dto;
|
||||
|
||||
public class BodylessMessage extends Message {
|
||||
public BodylessMessage(MessageType type) {
|
||||
this.setType(type);
|
||||
}
|
||||
|
||||
public BodylessMessage(MessageType type, String command) {
|
||||
this.setType(type);
|
||||
this.setBody(command);
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
package me.zinch.Lab6.Domain.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public abstract class Message implements Serializable {
|
||||
private MessageType type;
|
||||
private Serializable body;
|
||||
|
||||
public final MessageType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public final void setType(MessageType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public final Object getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public final void setBody(Serializable body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Message{" +
|
||||
"type=" + type +
|
||||
", body=" + body +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package me.zinch.Lab6.Domain.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MessageBody implements Serializable {
|
||||
private String command;
|
||||
private Serializable body;
|
||||
|
||||
public MessageBody(String command, Serializable body) {
|
||||
this.command = command;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public Serializable getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(Serializable body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package me.zinch.Lab6.Domain.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public enum MessageType implements Serializable {
|
||||
GET,
|
||||
POST,
|
||||
ERROR,
|
||||
OK,
|
||||
HELLO
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package me.zinch.Lab6.Domain.dto;
|
||||
|
||||
import me.zinch.Lab6.Domain.models.ProductDTO;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class UpdateBody implements Serializable {
|
||||
private Long id;
|
||||
private ProductDTO productDTO;
|
||||
|
||||
public UpdateBody(Long id, ProductDTO productDTO) {
|
||||
this.id = id;
|
||||
this.productDTO = productDTO;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ProductDTO getProductDTO() {
|
||||
return productDTO;
|
||||
}
|
||||
|
||||
public void setProductDTO(ProductDTO productDTO) {
|
||||
this.productDTO = productDTO;
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
package me.zinch.Lab6.Domain.wrapper;
|
||||
|
||||
import me.zinch.Lab6.Domain.models.Product;
|
||||
import me.zinch.Lab6.Domain.models.ProductDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IStorage {
|
||||
public Product getProductById(Long id);
|
||||
|
||||
public Product addProduct(ProductDTO productDTO);
|
||||
|
||||
public Product updateProduct(Long id, ProductDTO productDTO);
|
||||
|
||||
public Product removeProduct(Long id);
|
||||
|
||||
public String getInfo();
|
||||
|
||||
public void clear();
|
||||
|
||||
public Long getMaxPrice();
|
||||
|
||||
public Long getMinPrice();
|
||||
|
||||
public boolean isProductIdExists(Long id);
|
||||
|
||||
public Integer removeLover(Long id);
|
||||
|
||||
public String filterContainsName(String name);
|
||||
|
||||
public String getUniqueManufactureCost();
|
||||
|
||||
public List<Product> toList();
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>me.zinch</groupId>
|
||||
<artifactId>Lab6-Server</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Lab6-Server</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>8.0.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>jakarta.el</artifactId>
|
||||
<version>5.0.0-M1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.zinch</groupId>
|
||||
<artifactId>Lab6-Domain</artifactId>
|
||||
<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>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<version>3.7.1</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>me.zinch.Lab6.Server.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.6.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -1,14 +0,0 @@
|
||||
package me.zinch.Lab6.Server;
|
||||
|
||||
import me.zinch.Lab6.Server.console.Console;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Main class for running the application.
|
||||
*/
|
||||
public class App {
|
||||
public static void main(String[] args) throws IOException {
|
||||
Console.run();
|
||||
}
|
||||
}
|
||||
@ -1,185 +0,0 @@
|
||||
package me.zinch.Lab6.Server;
|
||||
|
||||
import me.zinch.Lab6.Domain.dto.BodylessMessage;
|
||||
import me.zinch.Lab6.Domain.dto.Message;
|
||||
import me.zinch.Lab6.Domain.dto.MessageBody;
|
||||
import me.zinch.Lab6.Domain.dto.MessageType;
|
||||
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;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Server {
|
||||
private static final Logger log = LoggerFactory.getLogger(Server.class);
|
||||
private final Selector selector;
|
||||
private final ServerSocketChannel serverSocketChannel;
|
||||
private final Map<SocketAddress, Message> usersMessages = new HashMap<>();
|
||||
private final IStorage storage;
|
||||
private boolean isRunning = false;
|
||||
|
||||
public Server(int port, IStorage collection) throws IOException {
|
||||
selector = Selector.open();
|
||||
serverSocketChannel = ServerSocketChannel.open();
|
||||
serverSocketChannel.bind(new InetSocketAddress(port));
|
||||
serverSocketChannel.configureBlocking(false);
|
||||
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
|
||||
isRunning = true;
|
||||
|
||||
if (collection == null) collection = new ProductCollection(new ArrayList<>());
|
||||
storage = collection;
|
||||
|
||||
log.info("The server has been assigned to port {}", port);
|
||||
}
|
||||
|
||||
public static ByteBuffer serialize(Serializable obj) throws IOException {
|
||||
try (var bOut = new ByteArrayOutputStream();
|
||||
var oOut = new ObjectOutputStream(bOut)) {
|
||||
oOut.writeObject(obj);
|
||||
oOut.flush();
|
||||
return ByteBuffer.wrap(bOut.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleKey(SelectionKey key) {
|
||||
try {
|
||||
if (key.isAcceptable()) handleAccept(key);
|
||||
if (key.isReadable()) handleRead(key);
|
||||
if (key.isWritable()) handleWrite(key);
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
key.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAccept(SelectionKey key) throws IOException {
|
||||
var server = (ServerSocketChannel) key.channel();
|
||||
var client = server.accept();
|
||||
if (client != null) {
|
||||
client.configureBlocking(false);
|
||||
client.register(selector, SelectionKey.OP_READ);
|
||||
log.info("Received connection from {}", client.getRemoteAddress());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRead(SelectionKey key) throws IOException, ClassNotFoundException {
|
||||
var client = (SocketChannel) key.channel();
|
||||
var buffer = ByteBuffer.allocate(8192);
|
||||
int bytesRead = client.read(buffer);
|
||||
if (bytesRead == -1) {
|
||||
client.close();
|
||||
} else {
|
||||
buffer.flip();
|
||||
var oIn = new ObjectInputStream(new ByteArrayInputStream(buffer.array()));
|
||||
var msg = (Message) oIn.readObject();
|
||||
log.info("Received message {} from {}", msg, client.getRemoteAddress());
|
||||
usersMessages.put(client.getRemoteAddress(), msg);
|
||||
client.register(selector, SelectionKey.OP_WRITE);
|
||||
oIn.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleWrite(SelectionKey key) throws IOException {
|
||||
var client = (SocketChannel) key.channel();
|
||||
var message = usersMessages.get(client.getRemoteAddress());
|
||||
if (message == null) {
|
||||
log.error("Message for {} not found", client.getRemoteAddress());
|
||||
client.close();
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBuffer responseBuffer = createResponse(message);
|
||||
if (responseBuffer != null) {
|
||||
client.write(responseBuffer);
|
||||
log.info("Sent message to {}", client.getRemoteAddress());
|
||||
}
|
||||
|
||||
client.close();
|
||||
}
|
||||
|
||||
private ByteBuffer createResponse(Message message) throws IOException {
|
||||
return switch (message.getType()) {
|
||||
case HELLO -> serialize(new BodylessMessage(MessageType.HELLO));
|
||||
case GET -> handleGetCommand((String) message.getBody());
|
||||
case POST -> handlePostCommand((MessageBody) message.getBody());
|
||||
default -> {
|
||||
log.error("Message type not supported");
|
||||
yield null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ByteBuffer handleGetCommand(String inputCommand) throws IOException {
|
||||
var command = CommandManager.getCommandByInput(inputCommand);
|
||||
if (command.isEmpty()) {
|
||||
log.error("Command {} not found", inputCommand);
|
||||
return serialize(new BodylessMessage(MessageType.ERROR, String.format("Command %s not found", inputCommand)));
|
||||
}
|
||||
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 {
|
||||
var inputCommand = request.getCommand();
|
||||
var body = request.getBody();
|
||||
|
||||
var command = CommandManager.getCommandByInput(inputCommand);
|
||||
if (command.isEmpty()) {
|
||||
log.error("Command {} not found", inputCommand);
|
||||
return serialize(new BodylessMessage(MessageType.ERROR, String.format("Command %s not found", inputCommand)));
|
||||
}
|
||||
|
||||
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 void stop() throws IOException {
|
||||
isRunning = false;
|
||||
serverSocketChannel.close();
|
||||
selector.close();
|
||||
DbController.saveDb(storage.toList());
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package me.zinch.Lab6.Server;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
import me.zinch.Lab6.Server.configs.ServerConfig;
|
||||
import me.zinch.Lab6.Server.wrapper.ProductCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ServerBuilder {
|
||||
private ServerConfig serverConfig = new ServerConfig();
|
||||
|
||||
public ServerBuilder() {
|
||||
serverConfig.setPort(3000);
|
||||
serverConfig.setCollection(new ProductCollection(new ArrayList<>()));
|
||||
}
|
||||
|
||||
public ServerBuilder(ServerConfig serverConfig) {
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
public ServerBuilder setPort(int port) {
|
||||
if (port < 1 || port > 65535) throw new IllegalArgumentException("Port must be between 1 and 65535");
|
||||
serverConfig.setPort(port);
|
||||
return new ServerBuilder(serverConfig);
|
||||
}
|
||||
|
||||
public ServerBuilder setCollection(IStorage collection) {
|
||||
serverConfig.setCollection(collection);
|
||||
return new ServerBuilder(serverConfig);
|
||||
}
|
||||
|
||||
public Server build() throws IOException {
|
||||
return new Server(serverConfig.getPort(),
|
||||
serverConfig.getCollection());
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
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 me.zinch.Lab6.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The Add class represents a command to add a new element to a collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class Add extends PostCommand {
|
||||
public Add() {
|
||||
super("add {element}", "добавить новый элемент в коллекцию", Pattern.compile("^add"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object object) throws CommandActionException {
|
||||
var productDTO = (ProductDTO) object;
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
var product = productCollection.addProduct(productDTO);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(String.format("Произошла ошибка при добавлении%n%s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
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 me.zinch.Lab6.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The AddIfMax class represents a command to add a new element to a collection if its price value exceeds the maximum price value in the collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class AddIfMax extends PostCommand {
|
||||
public AddIfMax() {
|
||||
super("add_if_max {element}", "добавить новый элемент в коллекцию, если его значение цены превышает значение наибольшей цены этой коллекции", Pattern.compile("^add_if_max .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object object) throws CommandActionException {
|
||||
try {
|
||||
var productDTO = (ProductDTO) object;
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
if (productCollection.getMaxPrice() == null || productCollection.getMaxPrice() < productDTO.getPrice()) {
|
||||
var product = productCollection.addProduct(productDTO);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
}
|
||||
return "Продукт не подходит под условие";
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
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 me.zinch.Lab6.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The AddIfMin class represents a command to add a new element to a collection if its price is lower than the lowest price in the collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class AddIfMin extends PostCommand {
|
||||
public AddIfMin() {
|
||||
super("add_if_min {element}", "добавить новый элемент в коллекцию, если его значение цены меньше, чем у наименьшей цены этой коллекции", Pattern.compile("^add_if_min .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object object) {
|
||||
try {
|
||||
var productDTO = (ProductDTO) object;
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
if (productCollection.getMinPrice() == null || productCollection.getMinPrice() > productDTO.getPrice()) {
|
||||
var product = productCollection.addProduct(productDTO);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
}
|
||||
return "Продукт не подходит под условие";
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Manages the registration and retrieval of commands.
|
||||
*/
|
||||
public class CommandManager {
|
||||
private static final List<Command> commandList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
registerCommand(new Show());
|
||||
registerCommand(new Exit());
|
||||
registerCommand(new Info());
|
||||
registerCommand(new Clear());
|
||||
registerCommand(new PrintAscending());
|
||||
registerCommand(new PrintUniqueManufactureCost());
|
||||
registerCommand(new FilterContainsName());
|
||||
registerCommand(new Add());
|
||||
registerCommand(new IsIdExists());
|
||||
registerCommand(new Update());
|
||||
registerCommand(new Remove());
|
||||
registerCommand(new AddIfMax());
|
||||
registerCommand(new AddIfMin());
|
||||
registerCommand(new RemoveLower());
|
||||
registerCommand(new Save());
|
||||
registerCommand(new GetProduct());
|
||||
|
||||
registerCommand(new Help());
|
||||
}
|
||||
|
||||
public static void registerCommand(Command command) {
|
||||
commandList.add(command);
|
||||
}
|
||||
|
||||
public static String getRegisteredCommand() {
|
||||
return String.join("\n", commandList
|
||||
.stream()
|
||||
.map(command -> String.format("%s - %s", command.getName(), command.getDescription()))
|
||||
.toList());
|
||||
}
|
||||
|
||||
public static Optional<Command> getCommandByInput(String input) {
|
||||
return commandList.stream().filter(command -> command.checkPattern(input)).findFirst();
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
import me.zinch.Lab6.Server.console.Console;
|
||||
|
||||
/**
|
||||
* A command to exit the program without saving to a file.
|
||||
*/
|
||||
public class Exit extends GetCommand {
|
||||
public Exit() {
|
||||
super("exit", "terminate the program (without saving to a file)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
Console.stopApp();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to filter elements whose 'name' field contains the specified substring.
|
||||
*/
|
||||
public class FilterContainsName extends PostCommand {
|
||||
public FilterContainsName() {
|
||||
super("filter_contains_name name", "вывести элементы, значение поля name которых содержит заданную подстроку", Pattern.compile("^filter_contains_name .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object object) {
|
||||
String name = object.toString();
|
||||
var result = productCollection.filterContainsName(name);
|
||||
return result.isEmpty() ? "Таких элементов не найдено" : result;
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
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 abstract class GetCommand extends Command {
|
||||
public GetCommand(String name, String description, Pattern pattern) {
|
||||
super(name, description, pattern);
|
||||
}
|
||||
|
||||
public GetCommand(String name, String description) {
|
||||
super(name, description);
|
||||
}
|
||||
|
||||
public abstract String action(IStorage productCollection) throws CommandActionException;
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
/**
|
||||
* A command to display help for available commands.
|
||||
*/
|
||||
public class Help extends GetCommand {
|
||||
public Help() {
|
||||
super("help", "display help for available commands");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
return SystemCommandManager.getRegisteredCommand();
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
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 IsIdExists extends PostCommand {
|
||||
public IsIdExists() {
|
||||
super("is_id_exists", "", Pattern.compile("^is_id_exists +."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object obj) throws CommandActionException {
|
||||
if (!productCollection.isProductIdExists((Long) obj))
|
||||
throw new CommandActionException("Продукт с таким ID не существует");
|
||||
return "Exists";
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
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 abstract class PostCommand extends Command {
|
||||
public PostCommand(String name, String description, Pattern pattern) {
|
||||
super(name, description, pattern);
|
||||
}
|
||||
|
||||
public PostCommand(String name, String description) {
|
||||
super(name, description);
|
||||
}
|
||||
|
||||
public abstract String action(IStorage productCollection, Object obj) throws CommandActionException;
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
/**
|
||||
* A command to print the elements of the collection in ascending order.
|
||||
*/
|
||||
public class PrintAscending extends GetCommand {
|
||||
public PrintAscending() {
|
||||
super("print_ascending", "вывести элементы коллекции в порядке возрастания");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
var result = productCollection.toString();
|
||||
return result.isEmpty() ? "Коллекция пуста" : result;
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
/**
|
||||
* A command to print the unique values of the 'manufactureCost' field of all elements in the collection.
|
||||
*/
|
||||
public class PrintUniqueManufactureCost extends GetCommand {
|
||||
public PrintUniqueManufactureCost() {
|
||||
super("print_unique_manufacture_cost", "вывести уникальные значения поля manufactureCost всех элементов в коллекции");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
var result = productCollection.getUniqueManufactureCost();
|
||||
return result.isEmpty() ? "Коллекция пуста" : result;
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* A command to remove an element from the collection by its id.
|
||||
*/
|
||||
public class Remove extends PostCommand {
|
||||
public Remove() {
|
||||
super("remove_by_id id", "удалить элемент из коллекции по его id", Pattern.compile("^remove_by_id .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object object) throws CommandActionException {
|
||||
try {
|
||||
Long id = (Long) object;
|
||||
if (productCollection.isProductIdExists(id)) {
|
||||
var product = productCollection.removeProduct(id);
|
||||
return String.format("Продукт %s был удалён", product.getName());
|
||||
}
|
||||
return "Продукта с таким id не существует";
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to remove all elements from the collection that have ids lower than the specified id.
|
||||
*/
|
||||
public class RemoveLower extends PostCommand {
|
||||
public RemoveLower() {
|
||||
super("remove_lower id", "удалить из коллекции все элементы, меньшие, чем заданный по id", Pattern.compile("^remove_lower .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object object) {
|
||||
try {
|
||||
Long id = (Long) object;
|
||||
var size = productCollection.removeLover(id);
|
||||
return String.format("Было удалено %d продуктов", size);
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
/**
|
||||
* A command to display all elements of the collection in string representation to the standard output stream.
|
||||
*/
|
||||
public class Show extends GetCommand {
|
||||
public Show() {
|
||||
super("show", "вывести в стандартный поток вывода все элементы коллекции в строковом представлении");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
var result = productCollection.toString();
|
||||
return result.isEmpty() ? "Коллекция пуста" : result;
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Manages the registration and retrieval of commands.
|
||||
*/
|
||||
public class SystemCommandManager {
|
||||
private static final List<Command> commandList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
registerCommand(new Exit());
|
||||
registerCommand(new Save());
|
||||
|
||||
registerCommand(new Help());
|
||||
}
|
||||
|
||||
public static void registerCommand(Command command) {
|
||||
commandList.add(command);
|
||||
}
|
||||
|
||||
public static String getRegisteredCommand() {
|
||||
return String.join("\n", commandList
|
||||
.stream()
|
||||
.map(command -> String.format("%s - %s", command.getName(), command.getDescription()))
|
||||
.toList());
|
||||
}
|
||||
|
||||
public static Optional<Command> getCommandByInput(String input) {
|
||||
return commandList.stream().filter(command -> command.checkPattern(input)).findFirst();
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
/**
|
||||
* Represents an unknown command.
|
||||
*/
|
||||
public class UnknownCommand extends GetCommand {
|
||||
public UnknownCommand() {
|
||||
super("", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
return "Команда не распознана.";
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.dto.MessageBody;
|
||||
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 me.zinch.Lab6.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to update the value of an element in the collection, whose id is specified.
|
||||
*/
|
||||
public class Update extends PostCommand {
|
||||
public Update() {
|
||||
super("update id {element}", "обновить значение элемента коллекции, id которого равен заданному", Pattern.compile("^update .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object object) throws CommandActionException {
|
||||
try {
|
||||
var body = (MessageBody) object;
|
||||
var id = Long.parseLong(body.getCommand().split(" ")[1]);
|
||||
if (productCollection.isProductIdExists(id)) {
|
||||
var productDTO = (ProductDTO) body.getBody();
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
var product = productCollection.updateProduct(id, productDTO);
|
||||
return String.format("Продукт %s был изменён", product.getName());
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
return "Продукта с таким id не существует";
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package me.zinch.Lab6.Server.configs;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
|
||||
public class ServerConfig {
|
||||
private Integer port;
|
||||
private IStorage collection;
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public IStorage getCollection() {
|
||||
return collection;
|
||||
}
|
||||
|
||||
public void setCollection(IStorage collection) {
|
||||
this.collection = collection;
|
||||
}
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
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;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Console class provides methods for interacting with the console, reading user input, and managing application flow.
|
||||
* This class includes methods for appending input history, stopping the application, reading product DTO from the console, and running the application loop.
|
||||
*/
|
||||
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;
|
||||
private static IStorage collection;
|
||||
|
||||
public static void stopApp() {
|
||||
showExitMessage();
|
||||
isRunning = false;
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public static void showExitMessage() {
|
||||
if (!isExitMessageShowed) log.info("Have a nice day!");
|
||||
isExitMessageShowed = true;
|
||||
}
|
||||
|
||||
public static void run() throws IOException, ValidationException {
|
||||
collection = new ProductCollection(DbController.loadDb());
|
||||
|
||||
var server = new ServerBuilder()
|
||||
.setPort(3000)
|
||||
.setCollection(collection)
|
||||
.build();
|
||||
|
||||
Console.handleInput();
|
||||
|
||||
server.run();
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
Console.stopApp();
|
||||
try {
|
||||
server.stop();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package me.zinch.Lab6.Server.exceptions;
|
||||
|
||||
public class ColorFormatException extends IllegalArgumentException {
|
||||
public ColorFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ColorFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package me.zinch.Lab6.Server.exceptions;
|
||||
|
||||
public class UnitOfMeasureFormatException extends IllegalArgumentException {
|
||||
public UnitOfMeasureFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UnitOfMeasureFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
95
README.md
95
README.md
@ -1,8 +1,99 @@
|
||||
# Лабораторная работа №6
|
||||
# Лабораторная работа №5
|
||||
|
||||
## Выполнил
|
||||
> ФИ: Зинченко Иван
|
||||
>
|
||||
> ИСУ: 408657
|
||||
>
|
||||
> Вариант: 21290
|
||||
> Вариант: 1632
|
||||
|
||||
## Задание
|
||||
Реализовать консольное приложение, которое реализует управление коллекцией объектов в интерактивном режиме.
|
||||
В коллекции необходимо хранить объекты класса `Product`, описание которого приведено ниже.
|
||||
|
||||
Разработанная программа должна удовлетворять следующим требованиям:
|
||||
- Класс, коллекцией экземпляров которого управляет программа, должен реализовывать сортировку по умолчанию.
|
||||
- Все требования к полям класса (указанные в виде комментариев) должны быть выполнены.
|
||||
- Для хранения необходимо использовать коллекцию типа `java.util.TreeSet`
|
||||
- При запуске приложения коллекция должна автоматически заполняться значениями из файла.
|
||||
- Имя файла должно передаваться программе с помощью: переменная окружения.
|
||||
- Данные должны храниться в файле в формате `xml`
|
||||
- Чтение данных из файла необходимо реализовать с помощью класса `java.io.BufferedInputStream`
|
||||
- Запись данных в файл необходимо реализовать с помощью класса `java.io.OutputStreamWriter`
|
||||
- Все классы в программе должны быть задокументированы в формате javadoc.
|
||||
- Программа должна корректно работать с неправильными данными (ошибки пользовательского ввода, отсутсвие прав доступа к файлу и т.п.).
|
||||
|
||||
В интерактивном режиме программа должна поддерживать выполнение следующих команд:
|
||||
- `help` : вывести справку по доступным командам
|
||||
- `info` : вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.)
|
||||
- `show` : вывести в стандартный поток вывода все элементы коллекции в строковом представлении
|
||||
- `add {element}` : добавить новый элемент в коллекцию
|
||||
- `update id {element}` : обновить значение элемента коллекции, id которого равен заданному
|
||||
- `remove_by_id id` : удалить элемент из коллекции по его id
|
||||
- `clear` : очистить коллекцию
|
||||
- `save` : сохранить коллекцию в файл
|
||||
- `execute_script file_name` : считать и исполнить скрипт из указанного файла. В скрипте содержатся команды в таком же виде, в котором их вводит пользователь в интерактивном режиме.
|
||||
- `exit` : завершить программу (без сохранения в файл)
|
||||
- `add_if_max {element}` : добавить новый элемент в коллекцию, если его значение превышает значение наибольшего элемента этой коллекции
|
||||
- `add_if_min {element}` : добавить новый элемент в коллекцию, если его значение меньше, чем у наименьшего элемента этой коллекции
|
||||
- `remove_lower {element}` : удалить из коллекции все элементы, меньшие, чем заданный
|
||||
- `filter_contains_name name` : вывести элементы, значение поля name которых содержит заданную подстроку
|
||||
- `print_ascending` : вывести элементы коллекции в порядке возрастания
|
||||
- `print_unique_manufacture_cost` : вывести уникальные значения поля manufactureCost всех элементов в коллекции
|
||||
|
||||
Формат ввода команд:
|
||||
- Все аргументы команды, являющиеся стандартными типами данных (примитивные типы, классы-оболочки, String, классы для хранения дат), должны вводиться в той же строке, что и имя команды.
|
||||
- Все составные типы данных (объекты классов, хранящиеся в коллекции) должны вводиться по одному полю в строку.
|
||||
- При вводе составных типов данных пользователю должно показываться приглашение к вводу, содержащее имя поля (например, "Введите дату рождения:")
|
||||
- Если поле является enum'ом, то вводится имя одной из его констант (при этом список констант должен быть предварительно выведен).
|
||||
- При некорректном пользовательском вводе (введена строка, не являющаяся именем константы в enum'е; введена строка вместо числа; введённое число не входит в указанные границы и т.п.) должно быть показано сообщение об ошибке и предложено повторить ввод поля.
|
||||
- Для ввода значений null использовать пустую строку.
|
||||
- Поля с комментарием "Значение этого поля должно генерироваться автоматически" не должны вводиться пользователем вручную при добавлении.
|
||||
|
||||
Описание хранимых в коллекции классов:
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private Long id; //Поле не может быть null, Значение поля должно быть больше 0, Значение этого поля должно быть уникальным, Значение этого поля должно генерироваться автоматически
|
||||
private String name; //Поле не может быть null, Строка не может быть пустой
|
||||
private Coordinates coordinates; //Поле не может быть null
|
||||
private java.time.ZonedDateTime creationDate; //Поле не может быть null, Значение этого поля должно генерироваться автоматически
|
||||
private Long price; //Поле не может быть null, Значение поля должно быть больше 0
|
||||
private String partNumber; //Длина строки не должна быть больше 82, Значение этого поля должно быть уникальным, Строка не может быть пустой, Поле может быть null
|
||||
private long manufactureCost;
|
||||
private UnitOfMeasure unitOfMeasure; //Поле не может быть null
|
||||
private Person owner; //Поле не может быть null
|
||||
}
|
||||
|
||||
public class Coordinates {
|
||||
private long x; //Максимальное значение поля: 883
|
||||
private Long y; //Значение поля должно быть больше -427, Поле не может быть null
|
||||
}
|
||||
|
||||
public class Person {
|
||||
private String name; //Поле не может быть null, Строка не может быть пустой
|
||||
private String passportID; //Длина строки должна быть не меньше 5, Длина строки не должна быть больше 22, Поле не может быть null
|
||||
private Color hairColor; //Поле может быть null
|
||||
private Location location; //Поле может быть null
|
||||
}
|
||||
|
||||
public class Location {
|
||||
private float x;
|
||||
private Integer y; //Поле не может быть null
|
||||
private String name; //Строка не может быть пустой, Поле может быть null
|
||||
}
|
||||
|
||||
public enum UnitOfMeasure {
|
||||
KILOGRAMS,
|
||||
CENTIMETERS,
|
||||
GRAMS
|
||||
}
|
||||
|
||||
public enum Color {
|
||||
GREEN,
|
||||
BLACK,
|
||||
BLUE,
|
||||
ORANGE,
|
||||
WHITE
|
||||
}
|
||||
```
|
||||
|
||||
2
db.xml
2
db.xml
@ -1 +1 @@
|
||||
<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>
|
||||
<Products><Product><id>341</id><name>ewreqr</name><coordinates><x>1432</x><y>132432</y></coordinates><creationDate>1711875600.000000000</creationDate><price>12324</price><partNumber>3214</partNumber><manufactureCost>342</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>324324</name><passportID>32143214</passportID><hairColor>WHITE</hairColor><location><x>342.0</x><y>423</y><name>214</name></location></owner></Product><Product><id>342</id><name>Hello</name><coordinates><x>13</x><y>4</y></coordinates><creationDate>1713267558.813808800</creationDate><price>12312</price><partNumber>312</partNumber><manufactureCost>321</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>123</name><passportID>431</passportID><hairColor>BLACK</hairColor><location><x>2321.0</x><y>432</y><name>31</name></location></owner></Product></Products>
|
||||
117
db.xml.example
Normal file
117
db.xml.example
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<Products>
|
||||
<Product>
|
||||
<id>1</id>
|
||||
<name>Product 1</name>
|
||||
<coordinates>
|
||||
<x>100</x>
|
||||
<y>50</y>
|
||||
</coordinates>
|
||||
<creationDate>2024-03-01T12:00:00Z</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>2024-03-01T12:05:00Z</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>2024-03-01T12:10:00Z</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>2024-03-01T12:15:00Z</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>2024-03-01T12:20:00Z</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>
|
||||
74
pom.xml
Normal file
74
pom.xml
Normal file
@ -0,0 +1,74 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>me.zinch</groupId>
|
||||
<artifactId>Lab5</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Lab5</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>8.0.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>jakarta.el</artifactId>
|
||||
<version>5.0.0-M1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<version>3.7.1</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>me.zinch.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.6.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
25
src/main/java/me/zinch/App.java
Normal file
25
src/main/java/me/zinch/App.java
Normal file
@ -0,0 +1,25 @@
|
||||
package me.zinch;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.console.ShutdownHook;
|
||||
import me.zinch.exceptions.ValidationException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Main class for running the application.
|
||||
*/
|
||||
public class App {
|
||||
public static void main(String[] args) {
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
||||
|
||||
try {
|
||||
Console.run();
|
||||
} catch (ValidationException e) {
|
||||
System.out.println("Ошибка при валидации БД. Некоторые данные не валидны.");
|
||||
System.out.println(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/main/java/me/zinch/commands/Add.java
Normal file
31
src/main/java/me/zinch/commands/Add.java
Normal file
@ -0,0 +1,31 @@
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.exceptions.CommandActionException;
|
||||
import me.zinch.exceptions.ValidationException;
|
||||
import me.zinch.validator.Validators;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The Add class represents a command to add a new element to a collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class Add extends Command {
|
||||
public Add() {
|
||||
super("add {element}", "добавить новый элемент в коллекцию", Pattern.compile("^add"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) throws CommandActionException {
|
||||
var productDTO = Console.readProductDTO();
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
var product = productCollection.addProduct(productDTO);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/main/java/me/zinch/commands/AddIfMax.java
Normal file
34
src/main/java/me/zinch/commands/AddIfMax.java
Normal file
@ -0,0 +1,34 @@
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.exceptions.CommandActionException;
|
||||
import me.zinch.exceptions.ValidationException;
|
||||
import me.zinch.validator.Validators;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The AddIfMax class represents a command to add a new element to a collection if its price value exceeds the maximum price value in the collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class AddIfMax extends Command {
|
||||
public AddIfMax() {
|
||||
super("add_if_max {element}", "добавить новый элемент в коллекцию, если его значение цены превышает значение наибольшей цены этой коллекции", Pattern.compile("^add_if_max \\d+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) throws CommandActionException {
|
||||
var productDTO = Console.readProductDTO();
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
if (productCollection.getMaxPrice() < productDTO.getPrice()) {
|
||||
var product = productCollection.addProduct(productDTO);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
}
|
||||
return "Продукт не подходит под условие";
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/main/java/me/zinch/commands/AddIfMin.java
Normal file
34
src/main/java/me/zinch/commands/AddIfMin.java
Normal file
@ -0,0 +1,34 @@
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.exceptions.CommandActionException;
|
||||
import me.zinch.exceptions.ValidationException;
|
||||
import me.zinch.validator.Validators;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The AddIfMin class represents a command to add a new element to a collection if its price is lower than the lowest price in the collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class AddIfMin extends Command {
|
||||
public AddIfMin() {
|
||||
super("add_if_min {element}", "добавить новый элемент в коллекцию, если его значение цены меньше, чем у наименьшей цены этой коллекции", Pattern.compile("^add_if_min \\d+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) {
|
||||
var productDTO = Console.readProductDTO();
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
if (productCollection.getMinPrice() > productDTO.getPrice()) {
|
||||
var product = productCollection.addProduct(productDTO);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
}
|
||||
return "Продукт не подходит под условие";
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,18 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* The Clear class represents a command to clear a collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class Clear extends GetCommand {
|
||||
public class Clear extends Command {
|
||||
public Clear() {
|
||||
super("clear", "очистить коллекцию");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
public String action(ProductCollection productCollection) {
|
||||
productCollection.clear();
|
||||
return "Коллекция была очищена";
|
||||
}
|
||||
@ -1,4 +1,7 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.exceptions.CommandActionException;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -37,4 +40,6 @@ public abstract class Command {
|
||||
public final boolean checkPattern(String input) {
|
||||
return pattern.matcher(input).matches();
|
||||
}
|
||||
|
||||
public abstract String action(ProductCollection productCollection) throws CommandActionException;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -10,25 +10,6 @@ import java.util.Optional;
|
||||
public class CommandManager {
|
||||
private static final List<Command> commandList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
registerCommand(new Show());
|
||||
registerCommand(new Exit());
|
||||
registerCommand(new Info());
|
||||
registerCommand(new Clear());
|
||||
registerCommand(new PrintAscending());
|
||||
registerCommand(new PrintUniqueManufactureCost());
|
||||
registerCommand(new FilterContainsName());
|
||||
registerCommand(new Add());
|
||||
registerCommand(new Update());
|
||||
registerCommand(new Remove());
|
||||
registerCommand(new AddIfMax());
|
||||
registerCommand(new AddIfMin());
|
||||
registerCommand(new RemoveLower());
|
||||
registerCommand(new ExecuteScript());
|
||||
|
||||
registerCommand(new Help());
|
||||
}
|
||||
|
||||
public static void registerCommand(Command command) {
|
||||
commandList.add(command);
|
||||
}
|
||||
@ -43,4 +24,24 @@ public class CommandManager {
|
||||
public static Optional<Command> getCommandByInput(String input) {
|
||||
return commandList.stream().filter(command -> command.checkPattern(input)).findFirst();
|
||||
}
|
||||
|
||||
static {
|
||||
registerCommand(new Show());
|
||||
registerCommand(new Exit());
|
||||
registerCommand(new Info());
|
||||
registerCommand(new Clear());
|
||||
registerCommand(new PrintAscending());
|
||||
registerCommand(new PrintUniqueManufactureCost());
|
||||
registerCommand(new FilterContainsName());
|
||||
registerCommand(new Add());
|
||||
registerCommand(new Update());
|
||||
registerCommand(new Remove());
|
||||
registerCommand(new AddIfMax());
|
||||
registerCommand(new AddIfMin());
|
||||
registerCommand(new RemoveLower());
|
||||
registerCommand(new Save());
|
||||
registerCommand(new ExecuteScript());
|
||||
|
||||
registerCommand(new Help());
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.Lab6.Client.files.ScriptLoader;
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.files.ScriptLoader;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -15,10 +15,6 @@ import java.util.regex.Pattern;
|
||||
public class ExecuteScript extends Command {
|
||||
private static final List<String> executeStack = new ArrayList<>();
|
||||
|
||||
public ExecuteScript() {
|
||||
super("execute_script file_name", "считать и исполнить скрипт из указанного файла. В скрипте содержатся команды в таком же виде, в котором их вводит пользователь в интерактивном режиме", Pattern.compile("^execute_script .+"));
|
||||
}
|
||||
|
||||
private void addFileToStack(String filePath) {
|
||||
executeStack.add(filePath);
|
||||
}
|
||||
@ -31,15 +27,17 @@ public class ExecuteScript extends Command {
|
||||
return executeStack.contains(filePath);
|
||||
}
|
||||
|
||||
public ExecuteScript() {
|
||||
super("execute_script file_name", "считать и исполнить скрипт из указанного файла. В скрипте содержатся команды в таком же виде, в котором их вводит пользователь в интерактивном режиме", Pattern.compile("^execute_script .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
public String action(ProductCollection productCollection) {
|
||||
try {
|
||||
var result = new StringBuilder();
|
||||
var scriptFile = Console.getLastCommand().split(" ")[1];
|
||||
result.append(String.format("Скрипт %s начинает работу.", scriptFile)).append("\n");
|
||||
addFileToStack(scriptFile);
|
||||
var commandList = ScriptLoader.loadList(scriptFile);
|
||||
for (var input : commandList) {
|
||||
for (var input: commandList) {
|
||||
input = input.trim();
|
||||
var command = CommandManager.getCommandByInput(input);
|
||||
if (command.isPresent()) {
|
||||
@ -49,14 +47,13 @@ public class ExecuteScript extends Command {
|
||||
if (checkFileInStack(nextFile)) continue;
|
||||
addFileToStack(nextFile);
|
||||
}
|
||||
result.append(command.get().action(client)).append("\n");
|
||||
command.get().action(productCollection);
|
||||
} else {
|
||||
new UnknownCommand().action(client);
|
||||
new UnknownCommand().action(productCollection);
|
||||
}
|
||||
}
|
||||
clearStack();
|
||||
result.append(String.format("Скрипт %s завершил работу.", scriptFile)).append("\n");
|
||||
return result.toString();
|
||||
return String.format("Скрипт %s завершил работу.%n", scriptFile);
|
||||
} catch (IOException e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.Lab6.Client.console.Console;
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* A command to exit the program without saving to a file.
|
||||
@ -12,8 +12,8 @@ public class Exit extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
Console.stopAppWithoutSaving();
|
||||
public String action(ProductCollection productCollection) {
|
||||
Console.stopApp();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
21
src/main/java/me/zinch/commands/FilterContainsName.java
Normal file
21
src/main/java/me/zinch/commands/FilterContainsName.java
Normal file
@ -0,0 +1,21 @@
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to filter elements whose 'name' field contains the specified substring.
|
||||
*/
|
||||
public class FilterContainsName extends Command {
|
||||
public FilterContainsName() {
|
||||
super("filter_contains_name name", "вывести элементы, значение поля name которых содержит заданную подстроку", Pattern.compile("^filter_contains_name \\w+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) {
|
||||
String name = Console.getLastCommand().split(" ")[1];
|
||||
return productCollection.filterContainsName(name);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* A command to display help for available commands.
|
||||
@ -11,7 +11,7 @@ public class Help extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
public String action(ProductCollection productCollection) {
|
||||
return CommandManager.getRegisteredCommand();
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,17 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* A command to display information about the collection (type, initialization date, number of elements, etc.) to the standard output stream.
|
||||
*/
|
||||
public class Info extends GetCommand {
|
||||
public class Info extends Command {
|
||||
public Info() {
|
||||
super("info", "вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) {
|
||||
public String action(ProductCollection productCollection) {
|
||||
return productCollection.getInfo();
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* A command to print the elements of the collection in ascending order.
|
||||
@ -7,4 +9,9 @@ public class PrintAscending extends Command {
|
||||
public PrintAscending() {
|
||||
super("print_ascending", "вывести элементы коллекции в порядке возрастания");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) {
|
||||
return productCollection.toString();
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* A command to print the unique values of the 'manufactureCost' field of all elements in the collection.
|
||||
@ -7,4 +9,9 @@ public class PrintUniqueManufactureCost extends Command {
|
||||
public PrintUniqueManufactureCost() {
|
||||
super("print_unique_manufacture_cost", "вывести уникальные значения поля manufactureCost всех элементов в коллекции");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) {
|
||||
return productCollection.getUniqueManufactureCost();
|
||||
}
|
||||
}
|
||||
22
src/main/java/me/zinch/commands/Remove.java
Normal file
22
src/main/java/me/zinch/commands/Remove.java
Normal file
@ -0,0 +1,22 @@
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to remove an element from the collection by its id.
|
||||
*/
|
||||
public class Remove extends Command {
|
||||
public Remove() {
|
||||
super("remove_by_id id", "удалить элемент из коллекции по его id", Pattern.compile("^remove_by_id \\d+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) {
|
||||
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
|
||||
var product = productCollection.removeProduct(id);
|
||||
return String.format("Продукт %s был удалён", product.getName());
|
||||
}
|
||||
}
|
||||
22
src/main/java/me/zinch/commands/RemoveLower.java
Normal file
22
src/main/java/me/zinch/commands/RemoveLower.java
Normal file
@ -0,0 +1,22 @@
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to remove all elements from the collection that have ids lower than the specified id.
|
||||
*/
|
||||
public class RemoveLower extends Command {
|
||||
public RemoveLower() {
|
||||
super("remove_lower id", "удалить из коллекции все элементы, меньшие, чем заданный по id", Pattern.compile("^remove_lower \\d+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) {
|
||||
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
|
||||
var size = productCollection.removeLover(id);
|
||||
return String.format("Было удалено %d продуктов", size);
|
||||
}
|
||||
}
|
||||
@ -1,21 +1,21 @@
|
||||
package me.zinch.Lab6.Server.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.Lab6.Domain.wrapper.IStorage;
|
||||
import me.zinch.Lab6.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab6.Server.files.DbController;
|
||||
import me.zinch.exceptions.CommandActionException;
|
||||
import me.zinch.files.DbController;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A command to save the collection to a file.
|
||||
*/
|
||||
public class Save extends GetCommand {
|
||||
public class Save extends Command {
|
||||
public Save() {
|
||||
super("save", "сохранить коллекцию в файл");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection) throws CommandActionException {
|
||||
public String action(ProductCollection productCollection) throws CommandActionException {
|
||||
try {
|
||||
DbController.saveDb(productCollection.toList());
|
||||
return "Коллекция была сохранена";
|
||||
@ -1,4 +1,6 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* A command to display all elements of the collection in string representation to the standard output stream.
|
||||
@ -7,4 +9,9 @@ public class Show extends Command {
|
||||
public Show() {
|
||||
super("show", "вывести в стандартный поток вывода все элементы коллекции в строковом представлении");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) {
|
||||
return productCollection.toString();
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package me.zinch.Lab6.Client.commands;
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.Lab6.Client.client.Client;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
/**
|
||||
* Represents an unknown command.
|
||||
@ -11,7 +11,7 @@ public class UnknownCommand extends Command {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
public String action(ProductCollection productCollection) {
|
||||
return "Команда не распознана.";
|
||||
}
|
||||
}
|
||||
34
src/main/java/me/zinch/commands/Update.java
Normal file
34
src/main/java/me/zinch/commands/Update.java
Normal file
@ -0,0 +1,34 @@
|
||||
package me.zinch.commands;
|
||||
|
||||
import me.zinch.console.Console;
|
||||
import me.zinch.exceptions.CommandActionException;
|
||||
import me.zinch.exceptions.ValidationException;
|
||||
import me.zinch.validator.Validators;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A command to update the value of an element in the collection, whose id is specified.
|
||||
*/
|
||||
public class Update extends Command {
|
||||
public Update() {
|
||||
super("update id {element}", "обновить значение элемента коллекции, id которого равен заданному", Pattern.compile("^update \\d+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(ProductCollection productCollection) throws CommandActionException {
|
||||
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
|
||||
if (productCollection.isProductIdExists(id)) {
|
||||
var productDTO = Console.readProductDTO();
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
var product = productCollection.updateProduct(id, productDTO);
|
||||
return String.format("Продукт %s был изменён", product.getName());
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
return "Продукта с таким id не существует";
|
||||
}
|
||||
}
|
||||
171
src/main/java/me/zinch/console/Console.java
Normal file
171
src/main/java/me/zinch/console/Console.java
Normal file
@ -0,0 +1,171 @@
|
||||
package me.zinch.console;
|
||||
|
||||
import me.zinch.commands.CommandManager;
|
||||
import me.zinch.exceptions.ColorFormatException;
|
||||
import me.zinch.exceptions.CommandActionException;
|
||||
import me.zinch.exceptions.IllegalProductDtoException;
|
||||
import me.zinch.exceptions.UnitOfMeasureFormatException;
|
||||
import me.zinch.exceptions.ValidationException;
|
||||
import me.zinch.files.DbController;
|
||||
import me.zinch.models.Color;
|
||||
import me.zinch.models.Coordinates;
|
||||
import me.zinch.models.Location;
|
||||
import me.zinch.models.Person;
|
||||
import me.zinch.models.ProductDTO;
|
||||
import me.zinch.models.UnitOfMeasure;
|
||||
import me.zinch.validator.ValidateResult;
|
||||
import me.zinch.validator.Validators;
|
||||
import me.zinch.wrapper.ProductCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.IllegalFormatConversionException;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
Console class provides methods for interacting with the console, reading user input, and managing application flow.
|
||||
This class includes methods for appending input history, stopping the application, reading product DTO from the console, and running the application loop.
|
||||
*/
|
||||
public class Console {
|
||||
private static final Scanner scanner = new Scanner(System.in);
|
||||
private static boolean isRunning = true;
|
||||
private static final List<String> history = new ArrayList<>();
|
||||
|
||||
public static void appendHistory(String input) {
|
||||
history.add(input);
|
||||
}
|
||||
|
||||
public static void stopApp() {
|
||||
isRunning = false;
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
public static String getLastCommand() {
|
||||
return history.get(history.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
private static String readString() {
|
||||
var input = scanner.nextLine().trim();
|
||||
return input.isEmpty() ? null : input;
|
||||
}
|
||||
|
||||
private static Long readLong() {
|
||||
var input = scanner.nextLine().trim();
|
||||
try {
|
||||
return Long.parseLong(input);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Color readColor() throws ColorFormatException {
|
||||
System.out.format("Цвет волос(%s): ", Color.getColorsString());
|
||||
var input = readString();
|
||||
if (input == null || input.isEmpty()) return null;
|
||||
try {
|
||||
return Color.create(Integer.parseInt(input));
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
try {
|
||||
return Color.create(input);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new ColorFormatException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static UnitOfMeasure readUnitOfMeasure() throws UnitOfMeasureFormatException {
|
||||
System.out.format("Единица измерения(%s): ", UnitOfMeasure.getUnitOfMeasuerString());
|
||||
var input = readString();
|
||||
try {
|
||||
return UnitOfMeasure.create(Integer.parseInt(input));
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
try {
|
||||
return UnitOfMeasure.create(input);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new ColorFormatException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Location readLocation() throws NumberFormatException {
|
||||
System.out.print("Создать поле Location? (Y/n): ");
|
||||
var input = readString();
|
||||
if (input != null && input.equalsIgnoreCase("n")) return null;
|
||||
System.out.print("Координата x локации: ");
|
||||
var locationX = Float.parseFloat(readString());
|
||||
System.out.print("Координата y локации: ");
|
||||
var locationY = Integer.parseInt(readString());
|
||||
System.out.print("Название: ");
|
||||
var locationName = readString();
|
||||
return new Location(locationX, locationY, locationName);
|
||||
}
|
||||
|
||||
public static ProductDTO readProductDTO() throws IllegalProductDtoException {
|
||||
try {
|
||||
var productDTO = new ProductDTO();
|
||||
System.out.println("Заполните следующие поля: ");
|
||||
System.out.print("Название: ");
|
||||
productDTO.setName(readString());
|
||||
System.out.print("Координата x: ");
|
||||
long x = readLong();
|
||||
System.out.print("Координата y: ");
|
||||
long y = readLong();
|
||||
productDTO.setCoordinates(new Coordinates(x, y));
|
||||
System.out.print("Цена: ");
|
||||
productDTO.setPrice(readLong());
|
||||
System.out.print("Номер части: ");
|
||||
productDTO.setPartNumber(readString());
|
||||
System.out.print("Себестоимость: ");
|
||||
productDTO.setManufactureCost(readLong());
|
||||
productDTO.setUnitOfMeasure(readUnitOfMeasure());
|
||||
System.out.print("Имя владельца: ");
|
||||
var ownerName = readString();
|
||||
System.out.print("Данные паспорта: ");
|
||||
var passportId = readString();
|
||||
Color color = readColor();
|
||||
productDTO.setOwner(new Person(ownerName, passportId, color, readLocation()));
|
||||
return productDTO;
|
||||
} catch (ColorFormatException | UnitOfMeasureFormatException e) {
|
||||
throw new IllegalProductDtoException(e.getMessage());
|
||||
} catch (NumberFormatException | NullPointerException | IllegalFormatConversionException e) {
|
||||
throw new IllegalProductDtoException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void run() throws IOException, ValidationException {
|
||||
var productList = DbController.loadDb();
|
||||
var validationResult = Validators.validateProductList(productList);
|
||||
if (!validationResult.stream().allMatch(ValidateResult::isValid)) {
|
||||
throw new ValidationException(String.join("\n", validationResult
|
||||
.stream()
|
||||
.map(ValidateResult::getMessage)
|
||||
.toList()));
|
||||
}
|
||||
var productCollection = new ProductCollection(productList);
|
||||
System.out.println("Добро пожаловать! Для просмотра команд введите help");
|
||||
while(isRunning) {
|
||||
System.out.print(":");
|
||||
try {
|
||||
var input = scanner.nextLine().trim();
|
||||
var command = CommandManager.getCommandByInput(input);
|
||||
if (command.isPresent()) {
|
||||
appendHistory(input);
|
||||
try {
|
||||
System.out.println(command.get().action(productCollection));
|
||||
} catch (CommandActionException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
System.out.println("Такой команды не существует. Напишите help, чтобы посмотреть список доступных команд.");
|
||||
}
|
||||
} catch (NoSuchElementException e) {
|
||||
stopApp();
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
System.out.println("Всего хорошего!");
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
package me.zinch.Lab6.Server.console;
|
||||
package me.zinch.console;
|
||||
|
||||
/**
|
||||
* Represents a shutdown hook that is executed when the application is stopped.
|
||||
*/
|
||||
public class ShutdownHook extends Thread {
|
||||
public ShutdownHook() {
|
||||
super();
|
||||
super(new Thread(Console::stopApp));
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package me.zinch.Lab6.Client.exceptions;
|
||||
package me.zinch.exceptions;
|
||||
|
||||
public class ColorFormatException extends IllegalArgumentException {
|
||||
public ColorFormatException() {
|
||||
@ -1,4 +1,4 @@
|
||||
package me.zinch.Lab6.Server.exceptions;
|
||||
package me.zinch.exceptions;
|
||||
|
||||
/**
|
||||
* Represents an exception that occurs during the execution of a command action.
|
||||
@ -1,4 +1,4 @@
|
||||
package me.zinch.Lab6.Server.exceptions;
|
||||
package me.zinch.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -9,8 +9,4 @@ public class DbInitializationException extends IOException {
|
||||
public DbInitializationException() {
|
||||
super("Ошибка! Не удалось инициализировать БД. Проверьте, что структура БД верна.");
|
||||
}
|
||||
|
||||
public DbInitializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package me.zinch.Lab6.Server.exceptions;
|
||||
package me.zinch.exceptions;
|
||||
|
||||
/**
|
||||
* Represents an exception that occurs when an illegal product DTO is encountered during the creation or modification of a product.
|
||||
@ -1,4 +1,4 @@
|
||||
package me.zinch.Lab6.Client.exceptions;
|
||||
package me.zinch.exceptions;
|
||||
|
||||
public class UnitOfMeasureFormatException extends IllegalArgumentException {
|
||||
public UnitOfMeasureFormatException() {
|
||||
@ -1,11 +1,10 @@
|
||||
package me.zinch.Lab6.Domain.exceptions;
|
||||
package me.zinch.exceptions;
|
||||
|
||||
/**
|
||||
* Represents an exception related to validation errors.
|
||||
*/
|
||||
public class ValidationException extends jakarta.validation.ValidationException {
|
||||
public ValidationException() {
|
||||
}
|
||||
public ValidationException() {}
|
||||
|
||||
public ValidationException(String message) {
|
||||
super(message);
|
||||
@ -1,18 +1,20 @@
|
||||
package me.zinch.Lab6.Server.files;
|
||||
package me.zinch.files;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.DatabindException;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import me.zinch.Lab6.Domain.models.Product;
|
||||
import me.zinch.exceptions.DbInitializationException;
|
||||
import me.zinch.models.Product;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -25,32 +27,10 @@ public class DbController {
|
||||
|
||||
static {
|
||||
Map<String, String> env = System.getenv();
|
||||
path = env.getOrDefault("DB_FILE", "db.xml");
|
||||
path = env.getOrDefault("DB_FILE", "");
|
||||
xmlMapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);
|
||||
}
|
||||
|
||||
public static List<Product> loadDb() {
|
||||
try {
|
||||
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));
|
||||
List<Product> collection = xmlMapper.readValue(bufferedInputStream, Products.class).getProducts();
|
||||
bufferedInputStream.close();
|
||||
if (collection == null) return new ArrayList<>();
|
||||
return collection;
|
||||
} catch (IOException e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveDb(List<Product> list) throws IOException {
|
||||
try {
|
||||
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(path));
|
||||
xmlMapper.writeValue(outputStreamWriter, new Products(list));
|
||||
outputStreamWriter.close();
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Не удалось записать в файл");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a collection of products.
|
||||
*/
|
||||
@ -59,8 +39,7 @@ public class DbController {
|
||||
@JacksonXmlProperty(localName = "Product")
|
||||
private List<Product> products;
|
||||
|
||||
public Products() {
|
||||
}
|
||||
public Products() {}
|
||||
|
||||
public Products(List<Product> list) {
|
||||
this.products = list;
|
||||
@ -70,4 +49,31 @@ public class DbController {
|
||||
return products;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Product> loadDb() throws IOException {
|
||||
try {
|
||||
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));
|
||||
Products collection = xmlMapper.readValue(bufferedInputStream, Products.class);
|
||||
bufferedInputStream.close();
|
||||
return collection.getProducts();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new FileNotFoundException("Не удалось найти файл " + path);
|
||||
} catch (DatabindException e) {
|
||||
throw new DbInitializationException();
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Произошла неожиданная ошибка во время работы с файлом!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveDb(List<Product> list) throws IOException {
|
||||
try {
|
||||
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(path));
|
||||
xmlMapper.writeValue(outputStreamWriter, new Products(list));
|
||||
outputStreamWriter.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new FileNotFoundException(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package me.zinch.Lab6.Server.files;
|
||||
package me.zinch.files;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
@ -1,6 +1,5 @@
|
||||
package me.zinch.Lab6.Domain.models;
|
||||
package me.zinch.models;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -8,7 +7,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
/**
|
||||
* Represents a color enumeration.
|
||||
*/
|
||||
public enum Color implements Serializable {
|
||||
public enum Color {
|
||||
GREEN("Зелёный"),
|
||||
BLACK("Чёрный"),
|
||||
BLUE("Синий"),
|
||||
@ -21,6 +20,10 @@ public enum Color implements Serializable {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
private String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public static Color create(String input) throws IllegalArgumentException {
|
||||
for (var unit : List.of(Color.values())) {
|
||||
if (unit.getColor().equalsIgnoreCase(input)) return unit;
|
||||
@ -39,10 +42,6 @@ public enum Color implements Serializable {
|
||||
.toList());
|
||||
}
|
||||
|
||||
private String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Color{" +
|
||||
@ -1,54 +1,32 @@
|
||||
package me.zinch.Lab6.Domain.models;
|
||||
package me.zinch.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import me.zinch.Lab6.Domain.exceptions.ValidationException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents coordinates with x and y values.
|
||||
*/
|
||||
public class Coordinates implements Serializable {
|
||||
public class Coordinates {
|
||||
@Max(value = 883, message = "Coordinates: Максимальное значение координаты x: 883")
|
||||
@JsonProperty("x")
|
||||
private long x; //Максимальное значение поля: 883
|
||||
|
||||
@NotNull(message = "Coordinates: Поле y не может быть null")
|
||||
@NotNull(message = "Coordinates: Поле не может быть null")
|
||||
@Min(value = -427, message = "Значение координаты y должно быть больше -427")
|
||||
@JsonProperty("y")
|
||||
private Long y; //Значение поля должно быть больше -427, Поле не может быть null
|
||||
|
||||
public Coordinates() {
|
||||
}
|
||||
public Coordinates() {}
|
||||
|
||||
public Coordinates(long x, Long y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public long getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(long x) {
|
||||
if (x > 883) throw new ValidationException("Максимальное значение координаты x: 883");
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public Long getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(Long y) {
|
||||
if (y == null) throw new ValidationException("Поле y не может быть null");
|
||||
if (y < -427) throw new ValidationException("Значение координаты y должно быть больше -427");
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Coordinates{" +
|
||||
@ -1,16 +1,15 @@
|
||||
package me.zinch.Lab6.Domain.models;
|
||||
package me.zinch.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import me.zinch.Lab6.Domain.validator.NotEmpty;
|
||||
import me.zinch.validator.NotEmpty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a location with x and y coordinates and a name.
|
||||
*/
|
||||
public class Location implements Serializable {
|
||||
public class Location {
|
||||
@JsonProperty("x")
|
||||
private float x;
|
||||
|
||||
@ -22,8 +21,7 @@ public class Location implements Serializable {
|
||||
@JsonProperty("name")
|
||||
private String name; //Строка не может быть пустой, Поле может быть null
|
||||
|
||||
public Location() {
|
||||
}
|
||||
public Location() {}
|
||||
|
||||
public Location(float x, Integer y, String name) {
|
||||
this.x = x;
|
||||
@ -1,18 +1,16 @@
|
||||
package me.zinch.Lab6.Domain.models;
|
||||
package me.zinch.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import me.zinch.Lab6.Domain.exceptions.ValidationException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a person with a name, passport ID, hair color, and location.
|
||||
*/
|
||||
public class Person implements Serializable {
|
||||
public class Person {
|
||||
@NotBlank(message = "Person: Имя персоны не может быть пустым или null")
|
||||
@JsonProperty("name")
|
||||
private String name; //Поле не может быть null, Строка не может быть пустой
|
||||
@ -28,8 +26,7 @@ public class Person implements Serializable {
|
||||
@JsonProperty("location")
|
||||
private Location location; //Поле может быть null
|
||||
|
||||
public Person() {
|
||||
}
|
||||
public Person() {}
|
||||
|
||||
public Person(String name, String passportID, Color hairColor, Location location) {
|
||||
this.name = name;
|
||||
@ -39,14 +36,10 @@ public class Person implements Serializable {
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
if (name == null || name.isEmpty()) throw new ValidationException("Имя персоны не может быть пустым или null");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setPassportID(String passportID) {
|
||||
if (passportID == null) throw new ValidationException("Поле passportID не может быть null");
|
||||
if (passportID.length() < 5 || passportID.length() > 22)
|
||||
throw new ValidationException("Длина строки passportID должна быть не меньше 5 и не должна быть больше 22");
|
||||
this.passportID = passportID;
|
||||
}
|
||||
|
||||
@ -1,20 +1,19 @@
|
||||
package me.zinch.Lab6.Domain.models;
|
||||
package me.zinch.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import me.zinch.Lab6.Domain.validator.NotEmpty;
|
||||
import me.zinch.validator.NotEmpty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a product with various attributes such as ID, name, coordinates, creation date, price, part number, manufacture cost, unit of measure, and owner.
|
||||
*/
|
||||
public class Product implements Serializable {
|
||||
public class Product {
|
||||
@NotNull(message = "Product: Поле id не может быть null")
|
||||
@Min(value = 1, message = "Product: Значение поля id должно быть больше 0")
|
||||
@JsonProperty("id")
|
||||
@ -53,19 +52,18 @@ public class Product implements Serializable {
|
||||
@JsonProperty("owner")
|
||||
private Person owner; //Поле не может быть null
|
||||
|
||||
public Product() {
|
||||
}
|
||||
public Product() {}
|
||||
|
||||
public Product(Long id,
|
||||
String name,
|
||||
Coordinates coordinates,
|
||||
ZonedDateTime creationDate,
|
||||
Long price,
|
||||
String partNumber,
|
||||
long manufactureCost,
|
||||
UnitOfMeasure unitOfMeasure,
|
||||
Person owner
|
||||
) {
|
||||
public Product (Long id,
|
||||
String name,
|
||||
Coordinates coordinates,
|
||||
ZonedDateTime creationDate,
|
||||
Long price,
|
||||
String partNumber,
|
||||
long manufactureCost,
|
||||
UnitOfMeasure unitOfMeasure,
|
||||
Person owner
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.coordinates = coordinates;
|
||||
@ -1,20 +1,20 @@
|
||||
package me.zinch.Lab6.Domain.models;
|
||||
package me.zinch.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import me.zinch.Lab6.Domain.exceptions.ValidationException;
|
||||
import me.zinch.Lab6.Domain.validator.NotEmpty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import me.zinch.validator.NotEmpty;
|
||||
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
* Represents a Data Transfer Object (DTO) for a product with attributes such as name, coordinates, price, part number, manufacture cost, unit of measure, and owner.
|
||||
*/
|
||||
public class ProductDTO implements Serializable {
|
||||
public class ProductDTO {
|
||||
@NotBlank(message = "ProductDTO: Строка name не может быть пустой или null")
|
||||
@JsonProperty("name")
|
||||
private String name; //Поле не может быть null, Строка не может быть пустой
|
||||
@ -24,7 +24,7 @@ public class ProductDTO implements Serializable {
|
||||
private Coordinates coordinates; //Поле не может быть null
|
||||
|
||||
@NotNull(message = "ProductDTO: Поле price не может быть null")
|
||||
@Min(value = 1, message = "ProductDTO: Значение поля price должно быть больше 0")
|
||||
@Min(value = 1, message = "Поле price не может быть null")
|
||||
@JsonProperty("price")
|
||||
private Long price; //Поле не может быть null, Значение поля должно быть больше 0
|
||||
|
||||
@ -44,8 +44,7 @@ public class ProductDTO implements Serializable {
|
||||
@JsonProperty("owner")
|
||||
private Person owner; //Поле не может быть null
|
||||
|
||||
public ProductDTO() {
|
||||
}
|
||||
public ProductDTO() {}
|
||||
|
||||
public ProductDTO(String name, Coordinates coordinates, Long price, String partNumber, long manufactureCost, UnitOfMeasure unitOfMeasure, Person owner) {
|
||||
this.name = name;
|
||||
@ -73,63 +72,55 @@ public class ProductDTO implements Serializable {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
if (name == null || name.isEmpty()) throw new ValidationException("Строка name не может быть пустой или null");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Coordinates getCoordinates() {
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
public void setCoordinates(Coordinates coordinates) {
|
||||
if (coordinates == null) throw new ValidationException("Поле coordinates не может быть null");
|
||||
this.coordinates = coordinates;
|
||||
}
|
||||
|
||||
public Long getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(Long price) {
|
||||
if (price == null) throw new ValidationException("Поле price не может быть null");
|
||||
if (price <= 0) throw new ValidationException("Поле price не может быть null");
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public String getPartNumber() {
|
||||
return partNumber;
|
||||
}
|
||||
|
||||
public void setPartNumber(String partNumber) {
|
||||
if (partNumber.isEmpty()) throw new ValidationException("Строка partNumber не может быть пустой");
|
||||
if (partNumber.length() > 82) throw new ValidationException("Длина строки partNumber не должна быть больше 82");
|
||||
this.partNumber = partNumber;
|
||||
}
|
||||
|
||||
public long getManufactureCost() {
|
||||
return manufactureCost;
|
||||
}
|
||||
|
||||
public void setManufactureCost(long manufactureCost) {
|
||||
this.manufactureCost = manufactureCost;
|
||||
}
|
||||
|
||||
public UnitOfMeasure getUnitOfMeasure() {
|
||||
return unitOfMeasure;
|
||||
}
|
||||
|
||||
public void setUnitOfMeasure(UnitOfMeasure unitOfMeasure) {
|
||||
if (unitOfMeasure == null) throw new ValidationException("Поле unitOfMeasure не может быть null");
|
||||
this.unitOfMeasure = unitOfMeasure;
|
||||
}
|
||||
|
||||
public Person getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setCoordinates(Coordinates coordinates) {
|
||||
this.coordinates = coordinates;
|
||||
}
|
||||
|
||||
public void setPrice(Long price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public void setPartNumber(String partNumber) {
|
||||
this.partNumber = partNumber;
|
||||
}
|
||||
|
||||
public void setManufactureCost(long manufactureCost) {
|
||||
this.manufactureCost = manufactureCost;
|
||||
}
|
||||
|
||||
public void setUnitOfMeasure(UnitOfMeasure unitOfMeasure) {
|
||||
this.unitOfMeasure = unitOfMeasure;
|
||||
}
|
||||
|
||||
public void setOwner(Person owner) {
|
||||
if (owner == null) throw new ValidationException("Поле owner не может быть null");
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user