From d9f51a1a21b9513e132e627298a1674e221fafe7 Mon Sep 17 00:00:00 2001 From: Alexander-D-Karpov Date: Wed, 7 Feb 2024 02:11:17 +0300 Subject: [PATCH] added base client-server files --- .gitignore | 29 +++++++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ .idea/workspace.xml | 100 +++++++++++++++++++++++++ README.md | 84 +++++++++++++++++++++ itmo-prog-lab-5.iml | 11 +++ src/Main.java | 10 +++ src/client/ClientApp.java | 46 ++++++++++++ src/client/ConsoleManager.java | 26 +++++++ src/common/enums/TicketType.java | 8 ++ src/common/models/Coordinates.java | 29 +++++++ src/common/models/Event.java | 37 +++++++++ src/common/models/Ticket.java | 90 ++++++++++++++++++++++ src/common/utils/TicketComparator.java | 4 + src/server/CollectionManager.java | 37 +++++++++ src/server/CommandProcessor.java | 35 +++++++++ src/server/FileManager.java | 36 +++++++++ src/server/ServerApp.java | 10 +++ src/server/commands/Command.java | 21 ++++++ src/server/commands/HelpCommand.java | 27 +++++++ src/server/commands/ShowCommand.java | 26 +++++++ 22 files changed, 686 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml create mode 100644 README.md create mode 100644 itmo-prog-lab-5.iml create mode 100644 src/Main.java create mode 100644 src/client/ClientApp.java create mode 100644 src/client/ConsoleManager.java create mode 100644 src/common/enums/TicketType.java create mode 100644 src/common/models/Coordinates.java create mode 100644 src/common/models/Event.java create mode 100644 src/common/models/Ticket.java create mode 100644 src/common/utils/TicketComparator.java create mode 100644 src/server/CollectionManager.java create mode 100644 src/server/CommandProcessor.java create mode 100644 src/server/FileManager.java create mode 100644 src/server/ServerApp.java create mode 100644 src/server/commands/Command.java create mode 100644 src/server/commands/HelpCommand.java create mode 100644 src/server/commands/ShowCommand.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..07115cd --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9cae477 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..168e596 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1707248583469 + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ed84ed --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# Лабраторная 5 + +## Текст задания +Реализовать консольное приложение, которое реализует управление коллекцией объектов в интерактивном режиме. В коллекции необходимо хранить объекты класса Ticket, описание которого приведено ниже. + +Разработанная программа должна удовлетворять следующим требованиям: + + Класс, коллекцией экземпляров которого управляет программа, должен реализовывать сортировку по умолчанию. + Все требования к полям класса (указанные в виде комментариев) должны быть выполнены. + Для хранения необходимо использовать коллекцию типа java.util.ArrayDequeue + При запуске приложения коллекция должна автоматически заполняться значениями из файла. + Имя файла должно передаваться программе с помощью: аргумент командной строки. + Данные должны храниться в файле в формате xml + Чтение данных из файла необходимо реализовать с помощью класса java.util.Scanner + Запись данных в файл необходимо реализовать с помощью класса java.io.OutputStreamWriter + Все классы в программе должны быть задокументированы в формате javadoc. + Программа должна корректно работать с неправильными данными (ошибки пользовательского ввода, отсутсвие прав доступа к файлу и т.п.). + +В интерактивном режиме программа должна поддерживать выполнение следующих команд: + + help : вывести справку по доступным командам + info : вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.) + show : вывести в стандартный поток вывода все элементы коллекции в строковом представлении + add {element} : добавить новый элемент в коллекцию + update id {element} : обновить значение элемента коллекции, id которого равен заданному + remove_by_id id : удалить элемент из коллекции по его id + clear : очистить коллекцию + save : сохранить коллекцию в файл + execute_script file_name : считать и исполнить скрипт из указанного файла. В скрипте содержатся команды в таком же виде, в котором их вводит пользователь в интерактивном режиме. + exit : завершить программу (без сохранения в файл) + remove_head : вывести первый элемент коллекции и удалить его + add_if_min {element} : добавить новый элемент в коллекцию, если его значение меньше, чем у наименьшего элемента этой коллекции + remove_greater {element} : удалить из коллекции все элементы, превышающие заданный + group_counting_by_type : сгруппировать элементы коллекции по значению поля type, вывести количество элементов в каждой группе + filter_by_event event : вывести элементы, значение поля event которых равно заданному + filter_less_than_type type : вывести элементы, значение поля type которых меньше заданного + +Формат ввода команд: + + Все аргументы команды, являющиеся стандартными типами данных (примитивные типы, классы-оболочки, String, классы для хранения дат), должны вводиться в той же строке, что и имя команды. + Все составные типы данных (объекты классов, хранящиеся в коллекции) должны вводиться по одному полю в строку. + При вводе составных типов данных пользователю должно показываться приглашение к вводу, содержащее имя поля (например, "Введите дату рождения:") + Если поле является enum'ом, то вводится имя одной из его констант (при этом список констант должен быть предварительно выведен). + При некорректном пользовательском вводе (введена строка, не являющаяся именем константы в enum'е; введена строка вместо числа; введённое число не входит в указанные границы и т.п.) должно быть показано сообщение об ошибке и предложено повторить ввод поля. + Для ввода значений null использовать пустую строку. + Поля с комментарием "Значение этого поля должно генерироваться автоматически" не должны вводиться пользователем вручную при добавлении. + +Описание хранимых в коллекции классов: +```java +public class Ticket { +private long id; //Значение поля должно быть больше 0, Значение этого поля должно быть уникальным, Значение этого поля должно генерироваться автоматически +private String name; //Поле не может быть null, Строка не может быть пустой +private Coordinates coordinates; //Поле не может быть null +private java.time.LocalDate creationDate; //Поле не может быть null, Значение этого поля должно генерироваться автоматически +private Long price; //Поле может быть null, Значение поля должно быть больше 0 +private Long discount; //Поле может быть null, Значение поля должно быть больше 0, Максимальное значение поля: 100 +private TicketType type; //Поле может быть null +private Event event; //Поле может быть null +} +public class Coordinates { +private int x; //Максимальное значение поля: 794 +private int y; +} +public class Event { +private int id; //Значение поля должно быть больше 0, Значение этого поля должно быть уникальным, Значение этого поля должно генерироваться автоматически +private String name; //Поле не может быть null, Строка не может быть пустой +private long ticketsCount; //Значение поля должно быть больше 0 +private String description; //Поле может быть null +private EventType eventType; //Поле может быть null +} +public enum TicketType { +VIP, +USUAL, +BUDGETARY, +CHEAP; +} +public enum EventType { +E_SPORTS, +FOOTBALL, +BASEBALL, +EXPOSITION; +} +``` + diff --git a/itmo-prog-lab-5.iml b/itmo-prog-lab-5.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/itmo-prog-lab-5.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Main.java b/src/Main.java new file mode 100644 index 0000000..bbe714c --- /dev/null +++ b/src/Main.java @@ -0,0 +1,10 @@ +import client.ClientApp; +import server.ServerApp; + +public class Main { + public static void main(String[] args) { + ServerApp serverApp = new ServerApp(); + ClientApp clientApp = new ClientApp(serverApp); + clientApp.start(); + } +} diff --git a/src/client/ClientApp.java b/src/client/ClientApp.java new file mode 100644 index 0000000..2b1adf3 --- /dev/null +++ b/src/client/ClientApp.java @@ -0,0 +1,46 @@ +package client; + +import server.ServerApp; + +import java.util.Scanner; + +public class ClientApp { + private ServerApp serverApp; + private Scanner scanner; + + public ClientApp(ServerApp serverApp) { + this.serverApp = serverApp; + this.scanner = new Scanner(System.in); + } + + public void start() { + System.out.println("Клиент запущен. Введите 'exit' для выхода."); + while (true) { + System.out.print("Введите команду: "); + if (!scanner.hasNextLine()) { // Проверка на EOF + System.out.println("Клиент завершает работу из-за отсутствия входных данных."); + break; + } + String input = scanner.nextLine(); + if ("exit".equalsIgnoreCase(input)) { + System.out.println("Клиент завершает работу."); + break; + } + String[] parts = input.split(" ", 2); + String commandName = parts[0]; + String[] args = parts.length > 1 ? new String[]{parts[1]} : new String[]{}; + String response = sendCommand(commandName, args); + System.out.println(response); + } + } + + public String sendCommand(String commandName, String[] args) { + return serverApp.executeCommand(commandName, args); + } + + public static void main(String[] args) { + ServerApp serverApp = new ServerApp(); + ClientApp clientApp = new ClientApp(serverApp); + clientApp.start(); + } +} diff --git a/src/client/ConsoleManager.java b/src/client/ConsoleManager.java new file mode 100644 index 0000000..736946b --- /dev/null +++ b/src/client/ConsoleManager.java @@ -0,0 +1,26 @@ +package client; + +import java.util.Scanner; + +public class ConsoleManager { + private final ClientApp clientApp; + private final Scanner scanner; + + public ConsoleManager(ClientApp clientApp) { + this.clientApp = clientApp; + this.scanner = new Scanner(System.in); + } + + public void run() { + while (true) { + System.out.print("Введите команду: "); + String input = scanner.nextLine(); + if ("exit".equalsIgnoreCase(input)) break; + String[] parts = input.split(" ", 2); + String commandName = parts[0]; + String[] args = parts.length > 1 ? new String[]{parts[1]} : new String[]{}; + String response = clientApp.sendCommand(commandName, args); + System.out.println(response); + } + } +} diff --git a/src/common/enums/TicketType.java b/src/common/enums/TicketType.java new file mode 100644 index 0000000..f39f3a5 --- /dev/null +++ b/src/common/enums/TicketType.java @@ -0,0 +1,8 @@ +package common.enums; + +public enum TicketType { + VIP, + USUAL, + BUDGETARY, + CHEAP; +} \ No newline at end of file diff --git a/src/common/models/Coordinates.java b/src/common/models/Coordinates.java new file mode 100644 index 0000000..b694af8 --- /dev/null +++ b/src/common/models/Coordinates.java @@ -0,0 +1,29 @@ +package common.models; + +public class Coordinates { + private double x; + private float y; + + // Конструктор + public Coordinates(double x, float y) { + this.x = x; + this.y = y; + } + + // Геттеры и сеттеры + public double getX() { + return x; + } + + public void setX(double x) { + this.x = x; + } + + public float getY() { + return y; + } + + public void setY(float y) { + this.y = y; + } +} diff --git a/src/common/models/Event.java b/src/common/models/Event.java new file mode 100644 index 0000000..0c5f0e7 --- /dev/null +++ b/src/common/models/Event.java @@ -0,0 +1,37 @@ +package common.models; + +public class Event { + private long id; + private String name; + private int ticketCount; + + public Event(long id, String name, int ticketCount) { + this.id = id; + this.name = name; + this.ticketCount = ticketCount; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getTicketCount() { + return ticketCount; + } + + public void setTicketCount(int ticketCount) { + this.ticketCount = ticketCount; + } +} diff --git a/src/common/models/Ticket.java b/src/common/models/Ticket.java new file mode 100644 index 0000000..89564e3 --- /dev/null +++ b/src/common/models/Ticket.java @@ -0,0 +1,90 @@ +package common.models; + +import common.enums.TicketType; + +import java.time.LocalDate; + +public class Ticket implements Comparable { + private static long nextId = 1; + private final long id; + private String name; + private Coordinates coordinates; + private final LocalDate creationDate; + private Long price; + private Long discount; + private TicketType type; + private Event event; + + public Ticket(String name, Coordinates coordinates, Long price, Long discount, TicketType type, Event event) { + this.id = nextId++; + this.name = name; + this.coordinates = coordinates; + this.creationDate = LocalDate.now(); + this.price = price; + this.discount = discount; + this.type = type; + this.event = event; + } + + @Override + public int compareTo(Ticket o) { + return Long.compare(this.id, o.id); + } + + // Геттеры и сеттеры + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Coordinates getCoordinates() { + return coordinates; + } + + public void setCoordinates(Coordinates coordinates) { + this.coordinates = coordinates; + } + + public LocalDate getCreationDate() { + return creationDate; + } + + public Long getPrice() { + return price; + } + + public void setPrice(Long price) { + this.price = price; + } + + public Long getDiscount() { + return discount; + } + + public void setDiscount(Long discount) { + this.discount = discount; + } + + public TicketType getType() { + return type; + } + + public void setType(TicketType type) { + this.type = type; + } + + public Event getEvent() { + return event; + } + + public void setEvent(Event event) { + this.event = event; + } +} \ No newline at end of file diff --git a/src/common/utils/TicketComparator.java b/src/common/utils/TicketComparator.java new file mode 100644 index 0000000..4c6d116 --- /dev/null +++ b/src/common/utils/TicketComparator.java @@ -0,0 +1,4 @@ +package common.utils; + +public class TicketComparator { +} diff --git a/src/server/CollectionManager.java b/src/server/CollectionManager.java new file mode 100644 index 0000000..80aa58c --- /dev/null +++ b/src/server/CollectionManager.java @@ -0,0 +1,37 @@ +package server; + +import server.commands.Command; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +public class CollectionManager { + private static final String CLASS_PATH = "server.commands.%sCommand"; + private static final String VALIDATION_ERROR_MESSAGE = "Ошибка валидации аргументов команды."; + private static final String EXECUTION_ERROR_MESSAGE = "Ошибка выполнения команды: "; + + public String executeCommand(String commandName, String[] args) { + try { + Command command = createCommand(commandName, args); + if (command.validate()) { + command.call(); + return command.getResult(); + } else { + return VALIDATION_ERROR_MESSAGE; + } + } catch (Exception e) { + return EXECUTION_ERROR_MESSAGE + e.getMessage(); + } + } + + private Command createCommand(String commandName, String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + Class commandClass = Class.forName(String.format(CLASS_PATH, commandName)); + Constructor constructor = commandClass.getConstructor(String[].class, CollectionManager.class); + return (Command) constructor.newInstance((Object) args, this); + } + + public String show() { + // Your logic to display the collection + return "Элементы коллекции: ..."; + } +} diff --git a/src/server/CommandProcessor.java b/src/server/CommandProcessor.java new file mode 100644 index 0000000..afbd063 --- /dev/null +++ b/src/server/CommandProcessor.java @@ -0,0 +1,35 @@ +package server; + +import server.commands.Command; + +public class CommandProcessor { + + public static String process(String commandLine, CollectionManager collectionManager) { + String[] parts = commandLine.trim().split(" ", 2); + String commandName = parts[0].toLowerCase(); + String[] args = parts.length > 1 ? new String[]{parts[1]} : new String[]{}; + + try { + String className = "server.commands." + Character.toUpperCase(commandName.charAt(0)) + commandName.substring(1) + "Command"; + Class clazz = Class.forName(className); + // Создание экземпляра команды с CollectionManager и args + Command command = (Command) clazz.getConstructor(CollectionManager.class, String[].class).newInstance(collectionManager, (Object)args); + + if (command.requiresArguments() && args.length == 0) { + return "Команда требует аргументы."; + } + + if (command.validate()) { + command.call(); + return command.getResult(); + } else { + return "Ошибка валидации аргументов команды."; + } + } catch (ClassNotFoundException e) { + return "Команда не найдена."; + } catch (Exception e) { + e.printStackTrace(); + return "Ошибка выполнения команды: " + e.getMessage(); + } + } +} diff --git a/src/server/FileManager.java b/src/server/FileManager.java new file mode 100644 index 0000000..8180298 --- /dev/null +++ b/src/server/FileManager.java @@ -0,0 +1,36 @@ +package server; + +import common.models.Ticket; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayDeque; +import java.util.Scanner; + +public class FileManager { + private final String fileName; + + public FileManager(String fileName) { + this.fileName = fileName; + } + + public ArrayDeque loadCollection() { + ArrayDeque tickets = new ArrayDeque<>(); + try (Scanner scanner = new Scanner(new File(fileName))) { + // Чтение и парсинг XML файла для заполнения коллекции tickets + // Примерный код, требуется реализация парсинга XML + } catch (FileNotFoundException e) { + System.err.println("Файл не найден: " + e.getMessage()); + } + return tickets; + } + + public void saveCollection(ArrayDeque tickets) { + try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8)) { + // Запись коллекции tickets в файл в формате XML + // Примерный код, требуется реализация форматирования и записи XML + } catch (IOException e) { + System.err.println("Ошибка при записи файла: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/server/ServerApp.java b/src/server/ServerApp.java new file mode 100644 index 0000000..264e89d --- /dev/null +++ b/src/server/ServerApp.java @@ -0,0 +1,10 @@ +package server; + +public class ServerApp { + private final CollectionManager collectionManager = new CollectionManager(); + + public String executeCommand(String command, String[] args) { + // Обработка команды и возвращение результата выполнения + return CommandProcessor.process(command, collectionManager); + } +} diff --git a/src/server/commands/Command.java b/src/server/commands/Command.java new file mode 100644 index 0000000..75ce7e9 --- /dev/null +++ b/src/server/commands/Command.java @@ -0,0 +1,21 @@ +package server.commands; + +public abstract class Command { + protected String[] args; + protected String result; + + public Command(String[] args) { + this.args = args; + } + + public abstract boolean validate(); + public abstract void call(); + public abstract boolean requiresArguments(); + + public String getResult() { + return result; + } + + public void setArgs(String[] args) { + } +} diff --git a/src/server/commands/HelpCommand.java b/src/server/commands/HelpCommand.java new file mode 100644 index 0000000..53c0ad7 --- /dev/null +++ b/src/server/commands/HelpCommand.java @@ -0,0 +1,27 @@ +package server.commands; + +import server.CollectionManager; + +public class HelpCommand extends Command { + private CollectionManager collectionManager; + + public HelpCommand(CollectionManager collectionManager, String[] args) { + super(args); + this.collectionManager = collectionManager; + } + + @Override + public boolean validate() { + return args.length == 0; + } + + @Override + public void call() { + result = "Список доступных команд: ..."; + } + + @Override + public boolean requiresArguments() { + return false; + } +} diff --git a/src/server/commands/ShowCommand.java b/src/server/commands/ShowCommand.java new file mode 100644 index 0000000..daa932b --- /dev/null +++ b/src/server/commands/ShowCommand.java @@ -0,0 +1,26 @@ +package server.commands; + +import server.CollectionManager; + +public class ShowCommand extends Command { + private CollectionManager collectionManager; + + public ShowCommand(CollectionManager collectionManager, String[] args) { + super(args); + this.collectionManager = collectionManager; + } + + @Override + public boolean validate() { + return args.length == 0; + } + + @Override + public void call() { + result = collectionManager.show(); + } + + public boolean requiresArguments() { + return false; + } +}