Merge branch 'lab7-dev' into develop
This commit is contained in:
commit
c23b171b5f
@ -1,13 +1,23 @@
|
||||
package me.zinch.Lab7.Server;
|
||||
|
||||
import me.zinch.Lab7.Server.console.Console;
|
||||
import me.zinch.Lab7.Server.utils.SHA256;
|
||||
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 {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Console.run();
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,13 +37,6 @@ public class CommandManager {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -9,13 +9,13 @@ import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class Login extends PostCommand {
|
||||
public class Login extends UnauthorizedCommand {
|
||||
public Login() {
|
||||
super("login", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object obj, User user) throws CommandActionException {
|
||||
public String action( Object obj) throws CommandActionException {
|
||||
try {
|
||||
var loginUser = (User) obj;
|
||||
if (DbWrapper.isUserExists(loginUser.getLogin(), SHA256.hash(loginUser.getPassword()), DbController.getConnection()))
|
||||
|
||||
@ -9,13 +9,12 @@ import me.zinch.Lab7.Server.wrapper.IStorage;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class Register extends PostCommand {
|
||||
public class Register extends UnauthorizedCommand {
|
||||
public Register() {
|
||||
super("register", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String action(IStorage productCollection, Object obj, User user) throws CommandActionException {
|
||||
public String action(Object obj) throws CommandActionException {
|
||||
try {
|
||||
var newUser = (User) obj;
|
||||
newUser.setPassword(SHA256.hash(newUser.getPassword()));
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
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;
|
||||
}
|
||||
@ -2,7 +2,7 @@ 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.server.ServerBuilder;
|
||||
import me.zinch.Lab7.Server.commands.GetCommand;
|
||||
import me.zinch.Lab7.Server.commands.SystemCommandManager;
|
||||
import me.zinch.Lab7.Server.configs.ServerConfig;
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
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,16 +1,22 @@
|
||||
package me.zinch.Lab7.Server.Server;
|
||||
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.exceptions.CommandActionException;
|
||||
import me.zinch.Lab7.Server.wrapper.ProductCollection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -24,7 +30,6 @@ import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -42,7 +47,6 @@ public class Server {
|
||||
serverSocket = new ServerSocket(port);
|
||||
isRunning = true;
|
||||
|
||||
if (collection == null) collection = new ProductCollection(new ArrayList<>());
|
||||
storage = collection;
|
||||
|
||||
log.info("The server has been assigned to port {}", port);
|
||||
@ -112,31 +116,32 @@ public class Server {
|
||||
}
|
||||
|
||||
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) user.setPassword(SHA256.hash(user.getPassword()));
|
||||
return switch (message.getType()) {
|
||||
case HELLO -> serialize(new BodylessMessage(MessageType.HELLO));
|
||||
case GET -> handleGetCommand((String) message.getBody(), user);
|
||||
case POST -> handlePostCommand((MessageBody) message.getBody(), user);
|
||||
default -> {
|
||||
log.error("Message type not supported");
|
||||
yield null;
|
||||
}
|
||||
};
|
||||
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()) {
|
||||
log.error("Command {} not found", inputCommand);
|
||||
return serialize(new BodylessMessage(MessageType.ERROR, String.format("Command %s not found", inputCommand)));
|
||||
}
|
||||
try {
|
||||
var action = (GetCommand) command.get();
|
||||
return serialize(new BodylessMessage(MessageType.OK, action.action(storage, user)));
|
||||
} catch (CommandActionException e) {
|
||||
return serialize(new BodylessMessage(MessageType.ERROR, e.getMessage()));
|
||||
}
|
||||
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 {
|
||||
@ -144,15 +149,25 @@ public class Server {
|
||||
var body = request.getBody();
|
||||
|
||||
var command = CommandManager.getCommandByInput(inputCommand);
|
||||
if (command.isEmpty()) {
|
||||
log.error("Command {} not found", inputCommand);
|
||||
return serialize(new BodylessMessage(MessageType.ERROR, String.format("Command %s not found", inputCommand)));
|
||||
}
|
||||
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 action = (PostCommand) command.get();
|
||||
return serialize(new BodylessMessage(MessageType.OK, action.action(storage, body, user)));
|
||||
} catch (CommandActionException e) {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
@ -1,15 +1,17 @@
|
||||
package me.zinch.Lab7.Server.Server;
|
||||
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 = new ProductCollection();
|
||||
private IStorage collection;
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
@ -32,7 +34,6 @@ public class ServerBuilder {
|
||||
|
||||
public ServerBuilder() {
|
||||
config.setPort(3000);
|
||||
config.setCollection(new ProductCollection(new ArrayList<>()));
|
||||
}
|
||||
|
||||
private ServerBuilder(Config config) {
|
||||
@ -0,0 +1,19 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,9 @@ 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);
|
||||
@ -196,6 +198,7 @@ public class DbWrapper {
|
||||
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());
|
||||
@ -280,4 +283,20 @@ public class DbWrapper {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ 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;
|
||||
|
||||
@ -15,7 +16,9 @@ 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;
|
||||
@ -26,9 +29,10 @@ import java.util.concurrent.locks.Lock;
|
||||
public class ProductCollection implements IStorage {
|
||||
private static final Logger log = LoggerFactory.getLogger(ProductCollection.class);
|
||||
private TreeSet<Product> productList;
|
||||
private Map<Long, String> productsOwners;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
private List<Product> fetchProductFromDb(Connection connection) {
|
||||
private List<Product> fetchProducts(Connection connection) {
|
||||
try {
|
||||
return DbWrapper.getProducts(connection);
|
||||
} catch (SQLException | FileNotFoundException e) {
|
||||
@ -37,25 +41,32 @@ public class ProductCollection implements IStorage {
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize(List<Product> list) {
|
||||
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));
|
||||
});
|
||||
productList.addAll(list);
|
||||
}
|
||||
productsOwners = new HashMap<>();
|
||||
|
||||
public ProductCollection(List<Product> list) {
|
||||
Initialize(list);
|
||||
}
|
||||
|
||||
public ProductCollection() {
|
||||
Initialize(new ArrayList<>());
|
||||
}
|
||||
|
||||
public ProductCollection(Connection connection) {
|
||||
Initialize(fetchProductFromDb(connection));
|
||||
productList.addAll(fetchProducts(connection));
|
||||
productsOwners.putAll(fetchProductsOwners(connection));
|
||||
}
|
||||
|
||||
public Product getProductById(Long id) {
|
||||
@ -83,7 +94,7 @@ public class ProductCollection implements IStorage {
|
||||
lock.lock();
|
||||
try {
|
||||
var product = DbWrapper.updateProduct(id, productDTO, DbController.getConnection(), user);
|
||||
fetchProductFromDb(DbController.getConnection());
|
||||
fetchDb();
|
||||
return productDTO.buildProduct(product.getId(), product.getCreationDate());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -119,7 +130,7 @@ public class ProductCollection implements IStorage {
|
||||
lock.lock();
|
||||
try {
|
||||
DbWrapper.clearProducts(user, DbController.getConnection());
|
||||
fetchProductFromDb(DbController.getConnection());
|
||||
fetchDb();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -157,7 +168,7 @@ public class ProductCollection implements IStorage {
|
||||
try {
|
||||
var size = productList.size();
|
||||
DbWrapper.removeLower(id, DbController.getConnection(), user);
|
||||
fetchProductFromDb(DbController.getConnection());
|
||||
fetchDb();
|
||||
return size - productList.size();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -203,7 +214,9 @@ public class ProductCollection implements IStorage {
|
||||
public String toString() {
|
||||
lock.lock();
|
||||
try {
|
||||
return String.join("\n", productList.stream().map(Product::toString).toList());
|
||||
return String.join("\n", productList.stream()
|
||||
.map(product -> String.format("%s by %s", product.toString(), productsOwners.getOrDefault(product.getId(), "Unknown")))
|
||||
.toList());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
DELETE FROM products_owners WHERE "user" = ?;
|
||||
|
||||
DELETE FROM products
|
||||
WHERE id IN (
|
||||
SELECT product FROM products_owners
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
SELECT product, login
|
||||
FROM products_owners
|
||||
LEFT JOIN users on products_owners."user" = users.id;
|
||||
Loading…
Reference in New Issue
Block a user