Compare commits
No commits in common. "lab8-dev" and "main" have entirely different histories.
2
.gitignore
vendored
2
.gitignore
vendored
@ -34,5 +34,3 @@ bin/
|
||||
target
|
||||
|
||||
*.scr
|
||||
|
||||
DB/*
|
||||
@ -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>Lab7-Client</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Lab7-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>Lab7-Domain</artifactId>
|
||||
<version>1.0</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.Lab7.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.Lab7.Client;
|
||||
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.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,64 +0,0 @@
|
||||
package me.zinch.Lab7.Client.client;
|
||||
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.ConnectionErrorException;
|
||||
import me.zinch.Lab7.Client.exceptions.ResponseException;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.Message;
|
||||
import me.zinch.Lab7.Domain.net.MessageType;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
|
||||
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;
|
||||
private User user;
|
||||
|
||||
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)) {
|
||||
|
||||
if (user != null) message.setUser(user);
|
||||
|
||||
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("Сервер не доступен");
|
||||
}
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public boolean isLogin() {
|
||||
return user != null;
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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,28 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CheckProductOwner extends Command {
|
||||
public CheckProductOwner() {
|
||||
super("check_product_owner", "");
|
||||
}
|
||||
|
||||
@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,11 +0,0 @@
|
||||
package me.zinch.Lab7.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.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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,19 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
|
||||
/**
|
||||
* A command to exit the program without saving to a file.
|
||||
*/
|
||||
public class Exit extends Command {
|
||||
public Exit() {
|
||||
super("exit", "завершить программу");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
Console.stopAppWithoutSaving();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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,17 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
|
||||
/**
|
||||
* A command to display help for available commands.
|
||||
*/
|
||||
public class Help extends Command {
|
||||
public Help() {
|
||||
super("help", "вывести справку по доступным командам");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) {
|
||||
return client.isLogin() ? MainCommandManager.getRegisteredCommand() : UserCommandManager.getRegisteredCommand();
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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,30 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.MessageType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Login extends Command {
|
||||
|
||||
public Login() {
|
||||
super("login", "войти в систему");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
var user = Console.readUser();
|
||||
try {
|
||||
var response = client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), user));
|
||||
if (response.getType() == MessageType.OK) {
|
||||
client.setUser(user);
|
||||
}
|
||||
return response.getBody().toString();
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
|
||||
public class Logout extends Command {
|
||||
public Logout() {
|
||||
super("logout", "выйти из текущего пользователя");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
client.setUser(null);
|
||||
return "Успешно!";
|
||||
}
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Manages the registration and retrieval of commands.
|
||||
*/
|
||||
public class MainCommandManager {
|
||||
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 Logout());
|
||||
|
||||
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,31 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.MessageType;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Register extends Command {
|
||||
|
||||
public Register() {
|
||||
super("register", "зарегистрироваться в системе");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(Client client) throws CommandActionException {
|
||||
var user = Console.readUser();
|
||||
try {
|
||||
var response = client.sendMessage(new BodyfulMessage(MessageType.POST, Console.getLastCommand(), user));
|
||||
if (response.getType() == MessageType.OK) {
|
||||
client.setUser(new User(user.getLogin(), user.getPassword()));
|
||||
}
|
||||
return response.getBody().toString();
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.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.Lab7.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,52 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.console.Console;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Domain.net.BodyfulMessage;
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.MessageBody;
|
||||
import me.zinch.Lab7.Domain.net.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 checkProductOwner = new CheckProductOwner();
|
||||
Console.appendHistory(String.format("%s %s", checkProductOwner.getSignature(), id));
|
||||
checkProductOwner.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,32 +0,0 @@
|
||||
package me.zinch.Lab7.Client.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class UserCommandManager {
|
||||
private static final List<Command> commandList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
registerCommand(new Login());
|
||||
registerCommand(new Register());
|
||||
registerCommand(new Exit());
|
||||
|
||||
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,229 +0,0 @@
|
||||
package me.zinch.Lab7.Client.console;
|
||||
|
||||
import me.zinch.Lab7.Client.client.Client;
|
||||
import me.zinch.Lab7.Client.commands.MainCommandManager;
|
||||
import me.zinch.Lab7.Client.commands.UserCommandManager;
|
||||
import me.zinch.Lab7.Client.exceptions.ColorFormatException;
|
||||
import me.zinch.Lab7.Client.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Client.exceptions.ConnectionErrorException;
|
||||
import me.zinch.Lab7.Client.exceptions.ResponseException;
|
||||
import me.zinch.Lab7.Client.exceptions.UnitOfMeasureFormatException;
|
||||
import me.zinch.Lab7.Domain.models.Color;
|
||||
import me.zinch.Lab7.Domain.models.Coordinates;
|
||||
import me.zinch.Lab7.Domain.models.Location;
|
||||
import me.zinch.Lab7.Domain.models.Person;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.models.UnitOfMeasure;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
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 String readPassword() {
|
||||
var msg = "Пароль пользователя";
|
||||
var console = System.console();
|
||||
return Objects.isNull(console) ? readField(msg) : Arrays.toString(console.readPassword(msg + ": "));
|
||||
}
|
||||
|
||||
public static User readUser() {
|
||||
var user = new User();
|
||||
log("Заполните следующие поля: ");
|
||||
|
||||
setField("Имя пользователя", () -> user.setLogin(readString()));
|
||||
setField(() -> user.setPassword(readPassword()));
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static void run() {
|
||||
while (client == null) {
|
||||
try {
|
||||
var address = readField("Хост");
|
||||
int port = Integer.parseInt(readField("Порт"));
|
||||
if (port > 65535 || port < 1) throw new NumberFormatException();
|
||||
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 = client.isLogin() ? MainCommandManager.getCommandByInput(input) : UserCommandManager.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.Lab7.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,11 +0,0 @@
|
||||
package me.zinch.Lab7.Client.exceptions;
|
||||
|
||||
public class ColorFormatException extends IllegalArgumentException {
|
||||
public ColorFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ColorFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.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.Lab7.Client.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ConnectionErrorException extends IOException {
|
||||
public ConnectionErrorException() {
|
||||
super("Произошла ошибка при подключении, сервер не доступен");
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
package me.zinch.Lab7.Client.exceptions;
|
||||
|
||||
public class ResponseException extends ClassNotFoundException {
|
||||
public ResponseException() {
|
||||
super("Ошибка при обработке данных от сервера.");
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package me.zinch.Lab7.Client.exceptions;
|
||||
|
||||
public class UnitOfMeasureFormatException extends IllegalArgumentException {
|
||||
public UnitOfMeasureFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UnitOfMeasureFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -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>Lab7-Domain</artifactId>
|
||||
<version>1.0</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,16 +0,0 @@
|
||||
package me.zinch.Lab7.Domain.net;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public BodyfulMessage(MessageType type, String command, Serializable body, User user) {
|
||||
this.setType(type);
|
||||
this.setBody(new MessageBody(command, body));
|
||||
this.setUser(user);
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.Domain.net;
|
||||
|
||||
public class BodylessMessage extends Message {
|
||||
public BodylessMessage(MessageType type) {
|
||||
this.setType(type);
|
||||
}
|
||||
|
||||
public BodylessMessage(MessageType type, String command) {
|
||||
this.setType(type);
|
||||
this.setBody(command);
|
||||
}
|
||||
|
||||
public BodylessMessage(MessageType type, String command, User user) {
|
||||
this.setType(type);
|
||||
this.setBody(command);
|
||||
this.setUser(user);
|
||||
}
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
package me.zinch.Lab7.Domain.net;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public abstract class Message implements Serializable {
|
||||
private MessageType type;
|
||||
private Serializable body;
|
||||
private Serializable user;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public Serializable getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(Serializable user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Message{" +
|
||||
"type=" + type +
|
||||
", body=" + body +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package me.zinch.Lab7.Domain.net;
|
||||
|
||||
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.Lab7.Domain.net;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public enum MessageType implements Serializable {
|
||||
GET,
|
||||
POST,
|
||||
ERROR,
|
||||
OK,
|
||||
HELLO
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package me.zinch.Lab7.Domain.net;
|
||||
|
||||
import me.zinch.Lab7.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,58 +0,0 @@
|
||||
package me.zinch.Lab7.Domain.net;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class User implements Serializable {
|
||||
@NotNull
|
||||
private String login;
|
||||
@NotNull
|
||||
private String password;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(String login, String password) {
|
||||
this.login = login;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
"login='" + login + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
User user = (User) o;
|
||||
return Objects.equals(login, user.login) && Objects.equals(password, user.password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(login, password);
|
||||
}
|
||||
}
|
||||
@ -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>Lab7-Server</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Lab7-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.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>Lab7-Domain</artifactId>
|
||||
<version>1.0</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>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.7.3</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.Lab7.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,23 +0,0 @@
|
||||
package me.zinch.Lab7.Server;
|
||||
|
||||
import me.zinch.Lab7.Server.console.Console;
|
||||
import me.zinch.Lab7.Server.exceptions.DbConnectionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Main class for running the application.
|
||||
*/
|
||||
public class App {
|
||||
private static final Logger log = LoggerFactory.getLogger(App.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
Console.run();
|
||||
} catch (IOException | DbConnectionException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.exceptions.ValidationException;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Domain.validator.Validators;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
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, User user) throws CommandActionException {
|
||||
var productDTO = (ProductDTO) object;
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
var product = productCollection.addProduct(productDTO, user);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
} catch (ValidationException | SQLException e) {
|
||||
throw new CommandActionException(String.format("Произошла ошибка при добавлении%n%s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.exceptions.ValidationException;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Domain.validator.Validators;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
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, User user) 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, user);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
}
|
||||
return "Продукт не подходит под условие";
|
||||
} catch (ValidationException | SQLException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.exceptions.ValidationException;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Domain.validator.Validators;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
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, User user) {
|
||||
try {
|
||||
var productDTO = (ProductDTO) object;
|
||||
try {
|
||||
Validators.validateObject(productDTO).throwIfNotValid();
|
||||
if (productCollection.getMinPrice() == null || productCollection.getMinPrice() > productDTO.getPrice()) {
|
||||
var product = productCollection.addProduct(productDTO, user);
|
||||
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
|
||||
}
|
||||
return "Продукт не подходит под условие";
|
||||
} catch (ValidationException | SQLException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.DbWrapper;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CheckProductOwner extends PostCommand {
|
||||
public CheckProductOwner() {
|
||||
super("check_product_owner", "", Pattern.compile("^check_product_owner .+"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object obj, User user) throws CommandActionException {
|
||||
try {
|
||||
var id = (long) obj;
|
||||
if (DbWrapper.hasAccess(id, user, DbController.getConnection())) return "Это ваш продукт";
|
||||
throw new CommandActionException("У вас нет прав на изменение данного продукта");
|
||||
} catch (ClassCastException e) {
|
||||
throw new CommandActionException(e);
|
||||
} catch (SQLException e) {
|
||||
throw new CommandActionException("У вас нет прав на изменение данного продукта");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The Clear class represents a command to clear a collection.
|
||||
* It extends the Command class.
|
||||
*/
|
||||
public class Clear extends GetCommand {
|
||||
public Clear() {
|
||||
super("clear", "очистить коллекцию");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, User user) {
|
||||
try {
|
||||
productCollection.clear(user);
|
||||
return "Были удалены ваши продукты";
|
||||
} catch (SQLException e) {
|
||||
throw new CommandActionException("Ошибка при отчистке коллекции");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.DbWrapper;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
public class Drop extends GetCommand{
|
||||
public Drop() {
|
||||
super("drop", "Init db");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, User user) throws CommandActionException {
|
||||
DbWrapper.dropDb();
|
||||
return "Dropped 💀";
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.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");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, User user) {
|
||||
Console.stopApp();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.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, User user) {
|
||||
String name = object.toString();
|
||||
var result = productCollection.filterContainsName(name);
|
||||
return result.isEmpty() ? "Таких элементов не найдено" : result;
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.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, User user) throws CommandActionException;
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.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, User user) throws CommandActionException {
|
||||
if (!productCollection.isProductIdExists((Long) obj))
|
||||
throw new CommandActionException("Продукт с таким ID не существует");
|
||||
return productCollection.getProductById((Long) obj).toString();
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.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, User user) {
|
||||
return SystemCommandManager.getRegisteredCommand();
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
/**
|
||||
* 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 Info() {
|
||||
super("info", "вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, User user) {
|
||||
return productCollection.getInfo();
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.DbInitializer;
|
||||
import me.zinch.Lab7.Server.wrapper.DbWrapper;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class Init extends GetCommand{
|
||||
public Init() {
|
||||
super("init", "Delete all db");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, User user) throws CommandActionException {
|
||||
try {
|
||||
DbInitializer.initializeDb(DbController.getConnection());
|
||||
return "Initialized 😇";
|
||||
} catch (SQLException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.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, User user) throws CommandActionException {
|
||||
if (!productCollection.isProductIdExists((Long) obj))
|
||||
throw new CommandActionException("Продукт с таким ID не существует");
|
||||
return "Exists";
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.utils.SHA256;
|
||||
import me.zinch.Lab7.Server.wrapper.DbWrapper;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class Login extends UnauthorizedCommand {
|
||||
public Login() {
|
||||
super("login", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action( Object obj) throws CommandActionException {
|
||||
try {
|
||||
var loginUser = (User) obj;
|
||||
if (DbWrapper.isUserExists(loginUser.getLogin(), SHA256.hash(loginUser.getPassword()), DbController.getConnection()))
|
||||
return "Здравствуйте, " + loginUser.getLogin() + "!";
|
||||
throw new CommandActionException("Ошибка в логине или пароле");
|
||||
} catch (SQLException e) {
|
||||
throw new CommandActionException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.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, User user) throws CommandActionException;
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.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, User user) {
|
||||
var result = productCollection.toString();
|
||||
return result.isEmpty() ? "Коллекция пуста" : result;
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.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, User user) {
|
||||
var result = productCollection.getUniqueManufactureCost();
|
||||
return result.isEmpty() ? "Коллекция пуста" : result;
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.utils.SHA256;
|
||||
import me.zinch.Lab7.Server.wrapper.DbWrapper;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class Register extends UnauthorizedCommand {
|
||||
public Register() {
|
||||
super("register", "");
|
||||
}
|
||||
|
||||
public String action(Object obj) throws CommandActionException {
|
||||
try {
|
||||
var newUser = (User) obj;
|
||||
newUser.setPassword(SHA256.hash(newUser.getPassword()));
|
||||
DbWrapper.createUser(newUser, DbController.getConnection());
|
||||
return "Пользователь создан";
|
||||
} catch (ClassCastException | SQLException e) {
|
||||
throw new CommandActionException("Пользователь уже существует");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
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, User user) throws CommandActionException {
|
||||
try {
|
||||
Long id = (Long) object;
|
||||
if (productCollection.isProductIdExists(id)) {
|
||||
var product = productCollection.removeProduct(id, user);
|
||||
return String.format("Продукт %s был удалён", product.getName());
|
||||
}
|
||||
return "Продукта с таким id не существует";
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
} catch (SQLException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
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, User user) {
|
||||
try {
|
||||
Long id = (Long) object;
|
||||
var size = productCollection.removeLover(id, user);
|
||||
return String.format("Было удалено %d продуктов", size);
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
} catch (SQLException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.DbWrapper;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
public class Seed extends GetCommand{
|
||||
public Seed() {
|
||||
super("seed", "Seed data");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, User user) throws CommandActionException {
|
||||
DbWrapper.seedDb();
|
||||
return "Seeded 🌿";
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.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, User user) {
|
||||
var result = productCollection.toString();
|
||||
return result.isEmpty() ? "Коллекция пуста" : result;
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package me.zinch.Lab7.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 Drop());
|
||||
registerCommand(new Init());
|
||||
registerCommand(new Seed());
|
||||
|
||||
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.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class UnauthorizedCommand extends Command {
|
||||
public UnauthorizedCommand(String name, String description, Pattern pattern) {
|
||||
super(name, description, pattern);
|
||||
}
|
||||
|
||||
public UnauthorizedCommand(String name, String description) {
|
||||
super(name, description);
|
||||
}
|
||||
|
||||
public abstract String action(Object obj) throws CommandActionException;
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
/**
|
||||
* Represents an unknown command.
|
||||
*/
|
||||
public class UnknownCommand extends GetCommand {
|
||||
public UnknownCommand() {
|
||||
super("", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, User user) {
|
||||
return "Команда не распознана.";
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package me.zinch.Lab7.Server.commands;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.MessageBody;
|
||||
import me.zinch.Lab7.Domain.exceptions.ValidationException;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Domain.validator.Validators;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
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, User user) 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, user);
|
||||
return String.format("Продукт %s был изменён", product.getName());
|
||||
} catch (ValidationException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
return "Продукта с таким id не существует";
|
||||
} catch (NumberFormatException e) {
|
||||
return "Неверный аргумент, id может быть только число";
|
||||
} catch (SQLException e) {
|
||||
throw new CommandActionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
package me.zinch.Lab7.Server.configs;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ServerConfig {
|
||||
private static final Logger log = LoggerFactory.getLogger(ServerConfig.class);
|
||||
private static final Properties properties = new Properties();
|
||||
|
||||
static {
|
||||
var settingsFile = new File("server.properties");
|
||||
if (settingsFile.isFile() && settingsFile.exists()) {
|
||||
try {
|
||||
properties.load(new FileReader(settingsFile));
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
var classLoader = ServerConfig.class.getClassLoader();
|
||||
try (var inputStream = classLoader.getResourceAsStream("server.properties")) {
|
||||
properties.load(inputStream);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getPort() {
|
||||
return Integer.parseInt(properties.getProperty("server-port", "3000"));
|
||||
}
|
||||
|
||||
public static String getDbHost() {
|
||||
return properties.getProperty("db-host", "localhost");
|
||||
}
|
||||
|
||||
public static int getDbPort() {
|
||||
return Integer.parseInt(properties.getProperty("db-port", "5432"));
|
||||
}
|
||||
|
||||
public static String getDbName() {
|
||||
return properties.getProperty("db-name", "studs");
|
||||
}
|
||||
|
||||
public static String getDbScheme() {
|
||||
return properties.getProperty("db-scheme", "s408657");
|
||||
}
|
||||
|
||||
public static String getDbUsername() {
|
||||
return properties.getProperty("db-username", "postgres");
|
||||
}
|
||||
|
||||
public static String getDbPassword() {
|
||||
return properties.getProperty("db-password", "postgres");
|
||||
}
|
||||
}
|
||||
@ -1,92 +0,0 @@
|
||||
package me.zinch.Lab7.Server.console;
|
||||
|
||||
import me.zinch.Lab7.Domain.exceptions.ValidationException;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.server.ServerBuilder;
|
||||
import me.zinch.Lab7.Server.commands.GetCommand;
|
||||
import me.zinch.Lab7.Server.commands.SystemCommandManager;
|
||||
import me.zinch.Lab7.Server.configs.ServerConfig;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.DbConnectionException;
|
||||
import me.zinch.Lab7.Server.wrapper.DbInitializer;
|
||||
import me.zinch.Lab7.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, DbConnectionException {
|
||||
DbController.initConnection();
|
||||
DbInitializer.initializeDb(DbController.getConnection());
|
||||
|
||||
collection = new ProductCollection(DbController.getConnection());
|
||||
|
||||
var server = new ServerBuilder()
|
||||
.setPort(ServerConfig.getPort())
|
||||
.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 {
|
||||
System.out.println(action.action(collection, null));
|
||||
} catch (CommandActionException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
System.out.println("This command does not exist. Write help to see a list of available commands.");
|
||||
}
|
||||
} catch (NoSuchElementException e) {
|
||||
stopApp();
|
||||
}
|
||||
}
|
||||
scanner.close();
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
package me.zinch.Lab7.Server.db;
|
||||
|
||||
import me.zinch.Lab7.Server.configs.ServerConfig;
|
||||
import me.zinch.Lab7.Server.exceptions.DbConnectionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* The DbController class provides methods for loading and saving product data to a database file.
|
||||
*/
|
||||
public class DbController {
|
||||
private static final Logger log = LoggerFactory.getLogger(DbController.class);
|
||||
private static Connection connection;
|
||||
|
||||
public static void initConnection() throws DbConnectionException {
|
||||
var url = String.format("jdbc:postgresql://%s:%s/%s?currentSchema=%s",
|
||||
ServerConfig.getDbHost(),
|
||||
ServerConfig.getDbPort(),
|
||||
ServerConfig.getDbName(),
|
||||
ServerConfig.getDbScheme());
|
||||
var props = new Properties();
|
||||
props.setProperty("user", ServerConfig.getDbUsername());
|
||||
props.setProperty("password", ServerConfig.getDbPassword());
|
||||
try {
|
||||
connection = DriverManager.getConnection(url, props);
|
||||
log.info("Connection to the database has been successfully established");
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new DbConnectionException("Failed to connect to the database");
|
||||
}
|
||||
}
|
||||
|
||||
public static Connection getConnection() throws DbConnectionException {
|
||||
if (connection == null) initConnection();
|
||||
return connection;
|
||||
}
|
||||
|
||||
public static void closeConnection() throws DbConnectionException {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new DbConnectionException("Failed to close the connection to the database");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package me.zinch.Lab7.Server.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Represents an exception that occurs when the database initialization fails.
|
||||
*/
|
||||
public class DbConnectionException extends SQLException {
|
||||
public DbConnectionException() {
|
||||
super("Failed to connect to the database");
|
||||
}
|
||||
|
||||
public DbConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package me.zinch.Lab7.Server.exceptions;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class DbExecuteException extends SQLException {
|
||||
public DbExecuteException() {
|
||||
super("Error during sql command execution");
|
||||
}
|
||||
|
||||
public DbExecuteException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
public DbExecuteException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package me.zinch.Lab7.Server.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,21 +0,0 @@
|
||||
package me.zinch.Lab7.Server.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NonExistentCommand extends IOException {
|
||||
public NonExistentCommand() {
|
||||
super("This command doesn't exist");
|
||||
}
|
||||
|
||||
public NonExistentCommand(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NonExistentCommand(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public NonExistentCommand(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package me.zinch.Lab7.Server.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class UnauthorizedException extends IOException {
|
||||
public UnauthorizedException() {
|
||||
super("Error during user validation");
|
||||
}
|
||||
|
||||
public UnauthorizedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnauthorizedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public UnauthorizedException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package me.zinch.Lab7.Server.files;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class FileReader {
|
||||
private static final Logger log = LoggerFactory.getLogger(FileReader.class);
|
||||
|
||||
public static String readFromInputStream(InputStream inputStream) {
|
||||
StringBuilder resultStringBuilder = new StringBuilder();
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
resultStringBuilder.append(line).append("\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
return "";
|
||||
}
|
||||
return resultStringBuilder.toString();
|
||||
}
|
||||
|
||||
public static String readFromResource(String fileName) throws FileNotFoundException {
|
||||
try (var inputStream = FileReader.class.getClassLoader().getResourceAsStream(fileName)) {
|
||||
return readFromInputStream(inputStream);
|
||||
} catch (IOException e) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,182 +0,0 @@
|
||||
package me.zinch.Lab7.Server.server;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.BodylessMessage;
|
||||
import me.zinch.Lab7.Domain.net.Message;
|
||||
import me.zinch.Lab7.Domain.net.MessageBody;
|
||||
import me.zinch.Lab7.Domain.net.MessageType;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.commands.UnauthorizedCommand;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.exceptions.DbExecuteException;
|
||||
import me.zinch.Lab7.Server.exceptions.NonExistentCommand;
|
||||
import me.zinch.Lab7.Server.exceptions.UnauthorizedException;
|
||||
import me.zinch.Lab7.Server.utils.SHA256;
|
||||
import me.zinch.Lab7.Server.wrapper.AuthGuard;
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.commands.CommandManager;
|
||||
import me.zinch.Lab7.Server.commands.GetCommand;
|
||||
import me.zinch.Lab7.Server.commands.PostCommand;
|
||||
import me.zinch.Lab7.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.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Server {
|
||||
private static final Logger log = LoggerFactory.getLogger(Server.class);
|
||||
private final ServerSocket serverSocket;
|
||||
private final IStorage storage;
|
||||
private boolean isRunning;
|
||||
private final ExecutorService requestReadPool = Executors.newCachedThreadPool();
|
||||
private final ExecutorService requestProcessPool = Executors.newCachedThreadPool();
|
||||
private final ExecutorService responseSendPool = Executors.newFixedThreadPool(12);
|
||||
|
||||
public Server(int port, IStorage collection) throws IOException {
|
||||
serverSocket = new ServerSocket(port);
|
||||
isRunning = true;
|
||||
|
||||
storage = collection;
|
||||
|
||||
log.info("The server has been assigned to port {}", port);
|
||||
}
|
||||
|
||||
public static byte[] serialize(Serializable obj) throws IOException {
|
||||
try (var bOut = new ByteArrayOutputStream();
|
||||
var oOut = new ObjectOutputStream(bOut)) {
|
||||
oOut.writeObject(obj);
|
||||
oOut.flush();
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
log.info("The server is running");
|
||||
|
||||
while (isRunning) {
|
||||
try {
|
||||
var clientSocket = serverSocket.accept();
|
||||
log.info("Received connection from {}", clientSocket.getRemoteSocketAddress());
|
||||
requestReadPool.execute(() -> {
|
||||
try {
|
||||
handleClient(clientSocket);
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleClient(Socket clientSocket) throws IOException, ClassNotFoundException {
|
||||
var inputStream = clientSocket.getInputStream();
|
||||
|
||||
var buffer = new byte[8192];
|
||||
inputStream.read(buffer);
|
||||
|
||||
var oIn = new ObjectInputStream(new ByteArrayInputStream(buffer));
|
||||
var msg = (Message) oIn.readObject();
|
||||
log.info("Received message {} from {}", msg, clientSocket.getRemoteSocketAddress());
|
||||
|
||||
responseSendPool.execute(() -> handleWrite(clientSocket, msg, inputStream));
|
||||
}
|
||||
|
||||
private void handleWrite(Socket clientSocket, Message msg, InputStream inputStream) {
|
||||
try {
|
||||
var response = requestProcessPool.submit(() -> createResponse(msg));
|
||||
var responseBuffer = response.get();
|
||||
if (responseBuffer != null) {
|
||||
try {
|
||||
var outputStream = clientSocket.getOutputStream();
|
||||
outputStream.write(responseBuffer);
|
||||
outputStream.flush();
|
||||
log.info("Sent message to {}", clientSocket.getRemoteSocketAddress());
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
inputStream.close();
|
||||
} catch (IOException | InterruptedException | ExecutionException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] createResponse(Message message) throws IOException {
|
||||
if (message.getType() == MessageType.HELLO) return serialize(new BodylessMessage(MessageType.HELLO));
|
||||
|
||||
var user = (User) message.getUser();
|
||||
if (user == null) return handleUnauthorizedCommand(message);
|
||||
user.setPassword(SHA256.hash(user.getPassword()));
|
||||
try {
|
||||
AuthGuard.throwIfUserNotValid(user);
|
||||
return switch (message.getType()) {
|
||||
case GET -> handleGetCommand((String) message.getBody(), user);
|
||||
case POST -> handlePostCommand((MessageBody) message.getBody(), user);
|
||||
default -> {
|
||||
log.error("Message type not supported");
|
||||
yield null;
|
||||
}
|
||||
};
|
||||
} catch (IOException | DbExecuteException | CommandActionException e) {
|
||||
return serialize(new BodylessMessage(MessageType.ERROR, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] handleGetCommand(String inputCommand, User user) throws IOException {
|
||||
var command = CommandManager.getCommandByInput(inputCommand);
|
||||
if (command.isEmpty()) throw new NonExistentCommand("Такой команды не существует");
|
||||
|
||||
var action = (GetCommand) command.get();
|
||||
return serialize(new BodylessMessage(MessageType.OK, action.action(storage, user)));
|
||||
}
|
||||
|
||||
private byte[] handlePostCommand(MessageBody request, User user) throws IOException {
|
||||
var inputCommand = request.getCommand();
|
||||
var body = request.getBody();
|
||||
|
||||
var command = CommandManager.getCommandByInput(inputCommand);
|
||||
if (command.isEmpty()) throw new NonExistentCommand("Такой команды не существует");
|
||||
|
||||
var action = (PostCommand) command.get();
|
||||
return serialize(new BodylessMessage(MessageType.OK, action.action(storage, body, user)));
|
||||
}
|
||||
|
||||
// Only get commands or else exception
|
||||
private byte[] handleUnauthorizedCommand(Message message) throws IOException {
|
||||
try {
|
||||
var messageBody = (MessageBody) message.getBody();
|
||||
var inputCommand = messageBody.getCommand();
|
||||
var body = messageBody.getBody();
|
||||
|
||||
var command = CommandManager.getCommandByInput(inputCommand);
|
||||
if (command.isEmpty()) throw new NonExistentCommand("Такой команды не существует");
|
||||
|
||||
var action = (UnauthorizedCommand) command.get();
|
||||
return serialize(new BodylessMessage(MessageType.OK, action.action(body)));
|
||||
} catch (ClassCastException | NonExistentCommand | CommandActionException e) {
|
||||
return serialize(new BodylessMessage(MessageType.ERROR, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() throws IOException {
|
||||
isRunning = false;
|
||||
serverSocket.close();
|
||||
requestReadPool.shutdown();
|
||||
requestProcessPool.shutdown();
|
||||
responseSendPool.shutdown();
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
package me.zinch.Lab7.Server.server;
|
||||
|
||||
import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
import me.zinch.Lab7.Server.wrapper.ProductCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
public class ServerBuilder {
|
||||
private static class Config {
|
||||
private int port = 3000;
|
||||
private IStorage collection;
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public IStorage getCollection() {
|
||||
return collection;
|
||||
}
|
||||
|
||||
public void setCollection(IStorage collection) {
|
||||
this.collection = collection;
|
||||
}
|
||||
}
|
||||
|
||||
private Config config = new Config();
|
||||
|
||||
public ServerBuilder() {
|
||||
config.setPort(3000);
|
||||
}
|
||||
|
||||
private ServerBuilder(Config config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public ServerBuilder setPort(int port) {
|
||||
if (port < 1 || port > 65535) throw new IllegalArgumentException("Port must be between 1 and 65535");
|
||||
config.setPort(port);
|
||||
return new ServerBuilder(config);
|
||||
}
|
||||
|
||||
public ServerBuilder setCollection(IStorage collection) {
|
||||
config.setCollection(collection);
|
||||
return new ServerBuilder(config);
|
||||
}
|
||||
|
||||
public Server build() throws IOException {
|
||||
return new Server(config.getPort(), config.getCollection());
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package me.zinch.Lab7.Server.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class SHA256 {
|
||||
public static String hash(String str) {
|
||||
if (str == null) str = "";
|
||||
MessageDigest digest;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
byte[] encodedhash = digest.digest(str.getBytes(StandardCharsets.UTF_8));
|
||||
StringBuilder hexString = new StringBuilder(2 * encodedhash.length);
|
||||
for (byte b : encodedhash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package me.zinch.Lab7.Server.wrapper;
|
||||
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.exceptions.DbExecuteException;
|
||||
import me.zinch.Lab7.Server.exceptions.UnauthorizedException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class AuthGuard {
|
||||
public static void throwIfUserNotValid(User user) throws UnauthorizedException, DbExecuteException {
|
||||
try {
|
||||
if (!DbWrapper.isUserExists(user, DbController.getConnection())) throw new UnauthorizedException("Ошибка при валидации пользователя");
|
||||
} catch (SQLException e) {
|
||||
throw new DbExecuteException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package me.zinch.Lab7.Server.wrapper;
|
||||
|
||||
import me.zinch.Lab7.Server.exceptions.DbConnectionException;
|
||||
import me.zinch.Lab7.Server.files.FileReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class DbInitializer {
|
||||
private static final Logger log = LoggerFactory.getLogger(DbInitializer.class);
|
||||
|
||||
public static void initializeDb(Connection connection) throws DbConnectionException {
|
||||
try (var st = connection.createStatement();
|
||||
var inputStream = DbInitializer.class.getClassLoader().getResourceAsStream("migrations/init.sql")) {
|
||||
try {
|
||||
st.executeQuery("SELECT * FROM db_info WHERE db_info.migration_version >= 1");
|
||||
log.info("The database already exists");
|
||||
} catch (SQLException e) {
|
||||
var initScript = FileReader.readFromInputStream(inputStream);
|
||||
st.execute(initScript);
|
||||
log.info("The database has been successfully initialized");
|
||||
}
|
||||
} catch (SQLException | IOException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,302 +0,0 @@
|
||||
package me.zinch.Lab7.Server.wrapper;
|
||||
|
||||
import me.zinch.Lab7.Domain.models.Product;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.files.FileReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DbWrapper {
|
||||
private static final Logger log = LoggerFactory.getLogger(DbWrapper.class);
|
||||
|
||||
public static List<Product> getProducts(Connection connection) throws SQLException, FileNotFoundException {
|
||||
try (var st = connection.createStatement()) {
|
||||
var productsResultSet = st.executeQuery(FileReader.readFromResource("migrations/getProducts.sql"));
|
||||
var products = new ArrayList<Product>();
|
||||
while (productsResultSet.next()) {
|
||||
products.add(Mapper.resultStateToProduct(productsResultSet));
|
||||
}
|
||||
return products;
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public static Product getProductByDto(ProductDTO productDTO, Connection connection) {
|
||||
try {
|
||||
var createProductStatement = connection.prepareStatement(FileReader.readFromResource("migrations/getProductByDto.sql"));
|
||||
|
||||
prepareProductDtoStatement(productDTO, createProductStatement);
|
||||
createProductStatement.setString(8, productDTO.getOwner().getName());
|
||||
createProductStatement.setString(9, productDTO.getOwner().getPassportID());
|
||||
createProductStatement.setInt(10, productDTO.getOwner().getHairColor().ordinal());
|
||||
createProductStatement.setFloat(11, productDTO.getOwner().getLocation().getX());
|
||||
createProductStatement.setInt(12, productDTO.getOwner().getLocation().getY());
|
||||
createProductStatement.setString(13, productDTO.getOwner().getLocation().getName());
|
||||
|
||||
var rs = createProductStatement.executeQuery();
|
||||
if (rs.next())
|
||||
return Mapper.resultStateToProduct(rs);
|
||||
return null;
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void prepareProductDtoStatement(ProductDTO productDTO, PreparedStatement createProductStatement) throws SQLException {
|
||||
createProductStatement.setString(1, productDTO.getName());
|
||||
createProductStatement.setLong(2, productDTO.getCoordinates().getX());
|
||||
createProductStatement.setLong(3, productDTO.getCoordinates().getY());
|
||||
createProductStatement.setLong(4, productDTO.getPrice());
|
||||
createProductStatement.setString(5, productDTO.getPartNumber());
|
||||
createProductStatement.setLong(6, productDTO.getManufactureCost());
|
||||
createProductStatement.setInt(7, productDTO.getUnitOfMeasure().ordinal());
|
||||
}
|
||||
|
||||
public static Product getProductById(long id, Connection connection) {
|
||||
try(var st = connection.prepareStatement(FileReader.readFromResource("migrations/getProductById.sql"))) {
|
||||
st.setLong(1, id);
|
||||
|
||||
var rs = st.executeQuery();
|
||||
if (rs.next()) {
|
||||
return Mapper.resultStateToProduct(rs);
|
||||
}
|
||||
return null;
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Product addProduct(ProductDTO productDTO, Connection connection, User user) throws SQLException {
|
||||
try {
|
||||
var createProductStatement = connection.prepareStatement(FileReader.readFromResource("migrations/createProduct.sql"), PreparedStatement.RETURN_GENERATED_KEYS);
|
||||
prepareProductObjectCreation(productDTO, connection);
|
||||
|
||||
createProductStatement.setString(1, productDTO.getName());
|
||||
createProductStatement.setLong(2, productDTO.getCoordinates().getX());
|
||||
createProductStatement.setLong(3, productDTO.getCoordinates().getY());
|
||||
createProductStatement.setTimestamp(4, Timestamp.valueOf(LocalDateTime.now()));
|
||||
createProductStatement.setLong(5, productDTO.getPrice());
|
||||
createProductStatement.setString(6, productDTO.getPartNumber());
|
||||
createProductStatement.setLong(7, productDTO.getManufactureCost());
|
||||
createProductStatement.setInt(8, productDTO.getUnitOfMeasure().ordinal());
|
||||
createProductStatement.setString(9, productDTO.getOwner().getPassportID());
|
||||
|
||||
createProductStatement.executeUpdate();
|
||||
var generatedKeys = createProductStatement.getGeneratedKeys();
|
||||
generatedKeys.next();
|
||||
|
||||
var product = getProductById(generatedKeys.getLong(1), connection);
|
||||
|
||||
var createProductOwnersStatement = connection.prepareStatement(FileReader.readFromResource("migrations/createProductOwners.sql"));
|
||||
createProductOwnersStatement.setLong(1, product.getId());
|
||||
createProductOwnersStatement.setLong(2, getUserId(user, connection));
|
||||
|
||||
createProductOwnersStatement.execute();
|
||||
|
||||
return product;
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Product updateProduct(long id, ProductDTO productDTO, Connection connection, User user) throws SQLException {
|
||||
try {
|
||||
if (!hasAccess(id, user, connection)) throw new SQLException("У вас нет прав на этот продукт");
|
||||
|
||||
var updateProductStatement = connection.prepareStatement(FileReader.readFromResource("migrations/updateProduct.sql"));
|
||||
prepareProductObjectCreation(productDTO, connection);
|
||||
|
||||
prepareProductDtoStatement(productDTO, updateProductStatement);
|
||||
updateProductStatement.setString(8, productDTO.getOwner().getPassportID());
|
||||
updateProductStatement.setLong(9, id);
|
||||
|
||||
updateProductStatement.execute();
|
||||
|
||||
return getProductByDto(productDTO, connection);
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void prepareProductObjectCreation(ProductDTO productDTO, Connection connection) throws SQLException, FileNotFoundException {
|
||||
var updateCoordinateStatement = connection.prepareStatement(FileReader.readFromResource("migrations/createCoordinate.sql"));
|
||||
var updateLocationStatement = connection.prepareStatement(FileReader.readFromResource("migrations/createLocation.sql"));
|
||||
var updatePersonStatement = connection.prepareStatement(FileReader.readFromResource("migrations/createPerson.sql"));
|
||||
|
||||
updateCoordinateStatement.setLong(1, productDTO.getCoordinates().getX());
|
||||
updateCoordinateStatement.setLong(2, productDTO.getCoordinates().getY());
|
||||
try {
|
||||
updateCoordinateStatement.execute();
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
|
||||
updateLocationStatement.setFloat(1, productDTO.getOwner().getLocation().getX());
|
||||
updateLocationStatement.setInt(2, productDTO.getOwner().getLocation().getY());
|
||||
updateLocationStatement.setString(3, productDTO.getOwner().getLocation().getName());
|
||||
try {
|
||||
updateLocationStatement.execute();
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
|
||||
updatePersonStatement.setString(1, productDTO.getOwner().getName());
|
||||
updatePersonStatement.setString(2, productDTO.getOwner().getPassportID());
|
||||
updatePersonStatement.setInt(3, productDTO.getOwner().getHairColor().ordinal());
|
||||
updatePersonStatement.setFloat(4, productDTO.getOwner().getLocation().getX());
|
||||
updatePersonStatement.setInt(5, productDTO.getOwner().getLocation().getY());
|
||||
try {
|
||||
updatePersonStatement.execute();
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean removeProductById(long id, Connection connection, User user) throws SQLException {
|
||||
if (!hasAccess(id, user, connection)) throw new SQLException("У вас нет прав на этот продукт");
|
||||
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/deleteProductById.sql"))) {
|
||||
st.setLong(1, id);
|
||||
st.setLong(2, id);
|
||||
return st.executeUpdate() > 0;
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static int removeLower(long id, Connection connection, User user) throws SQLException {
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/deleteLower.sql"))) {
|
||||
st.setLong(1, getUserId(user, connection));
|
||||
st.setLong(2, id);
|
||||
return st.executeUpdate();
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearProducts(User user, Connection connection) throws SQLException {
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/clearProducts.sql"))) {
|
||||
st.setLong(1, getUserId(user, connection));
|
||||
st.setLong(2, getUserId(user, connection));
|
||||
st.executeUpdate();
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isUserExists(User user, Connection connection) throws SQLException {
|
||||
return isUserExists(user.getLogin(), user.getPassword(), connection);
|
||||
}
|
||||
|
||||
public static boolean isUserExists(String login, String passwordHash, Connection connection) throws SQLException {
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/isUserExists.sql"))) {
|
||||
st.setString(1, login);
|
||||
st.setString(2, passwordHash);
|
||||
|
||||
var rs = st.executeQuery();
|
||||
return rs.next();
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static long getUserId(User user, Connection connection) throws SQLException {
|
||||
return getUserId(user.getLogin(), user.getPassword(), connection);
|
||||
}
|
||||
|
||||
public static long getUserId(String login, String passwordHash, Connection connection) throws SQLException {
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/isUserExists.sql"))) {
|
||||
st.setString(1, login);
|
||||
st.setString(2, passwordHash);
|
||||
|
||||
var rs = st.executeQuery();
|
||||
if (rs.next()) return rs.getLong(1);
|
||||
throw new SQLException("User not found");
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static User createUser(User userRegister, Connection connection) throws SQLException {
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/createUser.sql"))) {
|
||||
st.setString(1, userRegister.getLogin());
|
||||
st.setString(2, userRegister.getPassword());
|
||||
|
||||
st.execute();
|
||||
return new User(userRegister.getLogin(), userRegister.getPassword());
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasAccess(long productId, User user, Connection connection) throws SQLException {
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/hasUserAccess.sql"))) {
|
||||
st.setLong(1, productId);
|
||||
st.setString(2, user.getLogin());
|
||||
st.setString(3, user.getPassword());
|
||||
|
||||
var rs = st.executeQuery();
|
||||
return rs.next();
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException("У вас нет прав на изменение данного продукта");
|
||||
}
|
||||
}
|
||||
|
||||
public static void dropDb() {
|
||||
try (var st = DbController.getConnection().prepareStatement(FileReader.readFromResource("migrations/drop.sql"))) {
|
||||
st.execute();
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void seedDb() {
|
||||
try (var st = DbController.getConnection().prepareStatement(FileReader.readFromResource("migrations/seed.sql"))) {
|
||||
st.execute();
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<Long, String> getProductsOwners(Connection connection) throws SQLException {
|
||||
try (var st = connection.prepareStatement(FileReader.readFromResource("migrations/getProductsOwners.sql"))) {
|
||||
var productsOwners = new HashMap<Long, String>();
|
||||
var rs = st.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
productsOwners.put(rs.getLong(1), rs.getString(2));
|
||||
}
|
||||
|
||||
return productsOwners;
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
throw new SQLException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package me.zinch.Lab7.Server.wrapper;
|
||||
|
||||
import me.zinch.Lab7.Domain.models.Product;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.exceptions.DbConnectionException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
public interface IStorage {
|
||||
public Product getProductById(Long id);
|
||||
|
||||
public Product addProduct(ProductDTO productDTO, User user) throws SQLException;
|
||||
|
||||
public Product updateProduct(Long id, ProductDTO productDTO, User user) throws SQLException;
|
||||
|
||||
public Product removeProduct(Long id, User user) throws SQLException;
|
||||
|
||||
public String getInfo();
|
||||
|
||||
public void clear(User user) throws SQLException;
|
||||
|
||||
public Long getMaxPrice();
|
||||
|
||||
public Long getMinPrice();
|
||||
|
||||
public boolean isProductIdExists(Long id);
|
||||
|
||||
public Integer removeLover(Long id, User user) throws SQLException;
|
||||
|
||||
public String filterContainsName(String name);
|
||||
|
||||
public String getUniqueManufactureCost();
|
||||
|
||||
public List<Product> toList();
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package me.zinch.Lab7.Server.wrapper;
|
||||
|
||||
import me.zinch.Lab7.Domain.models.Color;
|
||||
import me.zinch.Lab7.Domain.models.Coordinates;
|
||||
import me.zinch.Lab7.Domain.models.Location;
|
||||
import me.zinch.Lab7.Domain.models.Person;
|
||||
import me.zinch.Lab7.Domain.models.Product;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.models.UnitOfMeasure;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class Mapper {
|
||||
public static Product resultStateToProduct(ResultSet resultSet) throws SQLException {
|
||||
var productDto = new ProductDTO();
|
||||
var coordinates = new Coordinates();
|
||||
var person = new Person();
|
||||
var location = new Location();
|
||||
productDto.setName(resultSet.getString(2));
|
||||
coordinates.setX(resultSet.getLong(3));
|
||||
coordinates.setY(resultSet.getLong(4));
|
||||
productDto.setPrice(resultSet.getLong(6));
|
||||
productDto.setPartNumber(resultSet.getString(7));
|
||||
productDto.setManufactureCost(resultSet.getLong(8));
|
||||
productDto.setUnitOfMeasure(UnitOfMeasure.create(resultSet.getInt(9)));
|
||||
person.setName(resultSet.getString(10));
|
||||
person.setPassportID(resultSet.getString(11));
|
||||
person.setHairColor(Color.create(resultSet.getInt(12)));
|
||||
location.setX(resultSet.getLong(13));
|
||||
location.setY(resultSet.getInt(14));
|
||||
location.setName(resultSet.getString(15));
|
||||
|
||||
person.setLocation(location);
|
||||
productDto.setOwner(person);
|
||||
productDto.setCoordinates(coordinates);
|
||||
|
||||
var id = resultSet.getLong(1);
|
||||
var date = ZonedDateTime.parse(String.join("T", resultSet.getString(5).split(" ")), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
return productDto.buildProduct(id, date);
|
||||
}
|
||||
}
|
||||
@ -1,249 +0,0 @@
|
||||
package me.zinch.Lab7.Server.wrapper;
|
||||
|
||||
import me.zinch.Lab7.Domain.models.Product;
|
||||
import me.zinch.Lab7.Domain.models.ProductDTO;
|
||||
import me.zinch.Lab7.Domain.net.User;
|
||||
import me.zinch.Lab7.Server.db.DbController;
|
||||
import me.zinch.Lab7.Server.exceptions.DbConnectionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
public class ProductCollection implements IStorage {
|
||||
private static final Logger log = LoggerFactory.getLogger(ProductCollection.class);
|
||||
private final TreeSet<Product> productList;
|
||||
private final Map<Long, String> productsOwners;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
private List<Product> fetchProducts(Connection connection) {
|
||||
try {
|
||||
return DbWrapper.getProducts(connection);
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
log.error(e.getMessage());
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Long, String> fetchProductsOwners(Connection connection) {
|
||||
try {
|
||||
return DbWrapper.getProductsOwners(connection);
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchDb() throws DbConnectionException {
|
||||
productList.clear();
|
||||
productList.addAll(fetchProducts(DbController.getConnection()));
|
||||
productsOwners.clear();
|
||||
productsOwners.putAll(fetchProductsOwners(DbController.getConnection()));
|
||||
}
|
||||
|
||||
public ProductCollection(Connection connection) {
|
||||
productList = new TreeSet<>((o1, o2) -> {
|
||||
var o1Length = Math.sqrt(o1.getCoordinates().getX() * o1.getCoordinates().getX() + o1.getCoordinates().getY() * o1.getCoordinates().getY());
|
||||
var o2Length = Math.sqrt(o2.getCoordinates().getX() * o2.getCoordinates().getX() + o2.getCoordinates().getY() * o2.getCoordinates().getY());
|
||||
return Math.toIntExact((long) (o1Length - o2Length));
|
||||
});
|
||||
productsOwners = new HashMap<>();
|
||||
|
||||
productList.addAll(fetchProducts(connection));
|
||||
productsOwners.putAll(fetchProductsOwners(connection));
|
||||
}
|
||||
|
||||
public Product getProductById(Long id) {
|
||||
lock.lock();
|
||||
try {
|
||||
Optional<Product> product = productList.stream().filter(i -> Objects.equals(i.getId(), id)).findFirst();
|
||||
return product.orElse(null);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Product addProduct(ProductDTO productDTO, User user) throws SQLException {
|
||||
lock.lock();
|
||||
try {
|
||||
var product = DbWrapper.addProduct(productDTO, DbController.getConnection(), user);
|
||||
productList.add(product);
|
||||
productsOwners.put(product.getId(), user.getLogin());
|
||||
return product;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Product updateProduct(Long id, ProductDTO productDTO, User user) throws SQLException {
|
||||
lock.lock();
|
||||
try {
|
||||
var product = DbWrapper.updateProduct(id, productDTO, DbController.getConnection(), user);
|
||||
fetchDb();
|
||||
return productDTO.buildProduct(product.getId(), product.getCreationDate());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Product removeProduct(Long id, User user) throws SQLException {
|
||||
lock.lock();
|
||||
try {
|
||||
var product = getProductById(id);
|
||||
if (DbWrapper.removeProductById(id, DbController.getConnection(), user)) {
|
||||
productList.remove(product);
|
||||
productsOwners.remove(product.getId());
|
||||
return product;
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public String getInfo() {
|
||||
lock.lock();
|
||||
try {
|
||||
var optionalInitDate = productList.stream().map(Product::getCreationDate).sorted().findFirst();
|
||||
ZonedDateTime initDate = optionalInitDate.orElse(ZonedDateTime.ofInstant(Instant.EPOCH, ZoneId.systemDefault()));
|
||||
return String.format("Структура: TreeSet%nДата инициализации: %s%nКоличество элементов: %s", initDate, productList.size());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(User user) throws SQLException {
|
||||
lock.lock();
|
||||
try {
|
||||
DbWrapper.clearProducts(user, DbController.getConnection());
|
||||
fetchDb();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Long getMaxPrice() {
|
||||
lock.lock();
|
||||
try {
|
||||
return productList.stream().max(Comparator.comparingLong(Product::getPrice)).map(Product::getPrice).orElse(null);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Long getMinPrice() {
|
||||
lock.lock();
|
||||
try {
|
||||
return productList.stream().min(Comparator.comparingLong(Product::getPrice)).map(Product::getPrice).orElse(null);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProductIdExists(Long id) {
|
||||
lock.lock();
|
||||
try {
|
||||
return getProductById(id) != null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Integer removeLover(Long id, User user) throws SQLException {
|
||||
lock.lock();
|
||||
try {
|
||||
var size = productList.size();
|
||||
DbWrapper.removeLower(id, DbController.getConnection(), user);
|
||||
fetchDb();
|
||||
return size - productList.size();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public String filterContainsName(String name) {
|
||||
lock.lock();
|
||||
try {
|
||||
return String.join("\n", productList.stream()
|
||||
.filter(product -> product.getName().toLowerCase().contains(name.toLowerCase()))
|
||||
.map(Product::toString)
|
||||
.toList());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public String getUniqueManufactureCost() {
|
||||
lock.lock();
|
||||
try {
|
||||
return String.join(", ", Set.copyOf(productList.stream()
|
||||
.map(Product::getManufactureCost)
|
||||
.toList())
|
||||
.stream()
|
||||
.map(Object::toString)
|
||||
.toList());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Product> toList() {
|
||||
lock.lock();
|
||||
try {
|
||||
return productList.stream().toList();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
lock.lock();
|
||||
try {
|
||||
return String.join("\n", productList.stream()
|
||||
.map(product -> String.format("%s by %s", product.toString(), productsOwners.getOrDefault(product.getId(), "Unknown")))
|
||||
.toList());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ProductCollection that = (ProductCollection) o;
|
||||
lock.lock();
|
||||
try {
|
||||
return Objects.equals(productList, that.productList);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
lock.lock();
|
||||
try {
|
||||
return Objects.hashCode(productList);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -1,8 +0,0 @@
|
||||
DELETE FROM products
|
||||
WHERE id IN (
|
||||
SELECT product FROM products_owners
|
||||
WHERE "user" = ?
|
||||
);
|
||||
|
||||
DELETE FROM products_owners WHERE "user" = ?;
|
||||
|
||||
@ -1 +0,0 @@
|
||||
INSERT INTO coordinates(x, y) VALUES (?, ?);
|
||||
@ -1 +0,0 @@
|
||||
INSERT INTO locations(x, y, name) VALUES (?, ?, ?);
|
||||
@ -1,2 +0,0 @@
|
||||
INSERT INTO persons(name, passport_id, color, location_x, location_y)
|
||||
VALUES (?, ?, ?, ?, ?);
|
||||
@ -1,2 +0,0 @@
|
||||
INSERT INTO products( name, coordinate_x, coordinate_y, creation_date, price, part_number, manufacture_cost, unit_of_measure, person)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
@ -1 +0,0 @@
|
||||
INSERT INTO products_owners(product, "user") VALUES (?, ?);
|
||||
@ -1,2 +0,0 @@
|
||||
INSERT INTO users(login, password)
|
||||
VALUES (?, ?);
|
||||
@ -1,6 +0,0 @@
|
||||
DELETE
|
||||
FROM products
|
||||
WHERE id IN (SELECT product
|
||||
FROM products_owners
|
||||
WHERE "user" = ?
|
||||
AND id < ?);
|
||||
@ -1,2 +0,0 @@
|
||||
DELETE FROM products_owners WHERE product = ?;
|
||||
DELETE FROM products WHERE id = ?;
|
||||
@ -1,7 +0,0 @@
|
||||
DROP TABLE IF EXISTS coordinates CASCADE;
|
||||
DROP TABLE IF EXISTS users CASCADE;
|
||||
DROP TABLE IF EXISTS locations CASCADE;
|
||||
DROP TABLE IF EXISTS db_info CASCADE;
|
||||
DROP TABLE IF EXISTS persons CASCADE;
|
||||
DROP TABLE IF EXISTS products_owners CASCADE;
|
||||
DROP TABLE IF EXISTS products CASCADE;
|
||||
@ -1,31 +0,0 @@
|
||||
SELECT id,
|
||||
products.name,
|
||||
coordinate_x,
|
||||
coordinate_y,
|
||||
creation_date,
|
||||
price,
|
||||
part_number,
|
||||
manufacture_cost,
|
||||
unit_of_measure,
|
||||
persons.name,
|
||||
persons.passport_id,
|
||||
persons.color,
|
||||
locations.x,
|
||||
locations.y,
|
||||
locations.name
|
||||
FROM products
|
||||
LEFT JOIN persons ON person = persons.passport_id
|
||||
LEFT JOIN locations on persons.location_x = locations.x and persons.location_y = locations.y
|
||||
WHERE products.name = ?
|
||||
AND coordinate_x = ?
|
||||
AND coordinate_y = ?
|
||||
AND price = ?
|
||||
AND part_number = ?
|
||||
AND manufacture_cost = ?
|
||||
AND unit_of_measure = ?
|
||||
AND persons.name = ?
|
||||
AND persons.passport_id = ?
|
||||
AND persons.color = ?
|
||||
AND locations.x = ?
|
||||
AND locations.y = ?
|
||||
AND locations.name = ?;
|
||||
@ -1,19 +0,0 @@
|
||||
SELECT id,
|
||||
products.name,
|
||||
coordinate_x,
|
||||
coordinate_y,
|
||||
creation_date,
|
||||
price,
|
||||
part_number,
|
||||
manufacture_cost,
|
||||
unit_of_measure,
|
||||
persons.name,
|
||||
persons.passport_id,
|
||||
persons.color,
|
||||
locations.x,
|
||||
locations.y,
|
||||
locations.name
|
||||
FROM products
|
||||
LEFT JOIN persons ON person = persons.passport_id
|
||||
LEFT JOIN locations on persons.location_x = locations.x and persons.location_y = locations.y
|
||||
WHERE id = ?;
|
||||
@ -1,18 +0,0 @@
|
||||
SELECT id,
|
||||
products.name,
|
||||
coordinate_x,
|
||||
coordinate_y,
|
||||
creation_date,
|
||||
price,
|
||||
part_number,
|
||||
manufacture_cost,
|
||||
unit_of_measure,
|
||||
persons.name,
|
||||
persons.passport_id,
|
||||
persons.color,
|
||||
locations.x,
|
||||
locations.y,
|
||||
locations.name
|
||||
FROM products
|
||||
LEFT JOIN persons ON person = persons.passport_id
|
||||
LEFT JOIN locations on persons.location_x = locations.x and persons.location_y = locations.y;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user