Compare commits

..

11 Commits

28 changed files with 354 additions and 108 deletions

27
Dockerfile Normal file
View File

@ -0,0 +1,27 @@
#
# Build stage
#
FROM maven:3.9.3-eclipse-temurin-17-alpine AS build
WORKDIR /home/app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean javadoc:javadoc package
#
# Generate index.html
#
FROM pandoc/core:3.1-ubuntu as mainPage
WORKDIR /home/app
COPY README.md .
RUN pandoc -s -o index.html README.md
#
# Package stage
#
FROM nginx:stable-alpine
COPY --from=build /home/app/target/site /usr/share/nginx/html
COPY --from=build /home/app/target/Lab5-1.0-jar-with-dependencies.jar /usr/share/nginx/html/app.jar
COPY --from=mainPage /home/app/index.html /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 80

View File

@ -7,47 +7,86 @@
>
> Вариант: 1632
## Результат
- [Ссылка на файл](/app.jar)
- [Документация](/apidocs/index.html)
## Задание
Реализовать консольное приложение, которое реализует управление коллекцией объектов в интерактивном режиме.
В коллекции необходимо хранить объекты класса `Product`, описание которого приведено ниже.
Разработанная программа должна удовлетворять следующим требованиям:
- Класс, коллекцией экземпляров которого управляет программа, должен реализовывать сортировку по умолчанию.
- Все требования к полям класса (указанные в виде комментариев) должны быть выполнены.
- Для хранения необходимо использовать коллекцию типа `java.util.TreeSet`
- При запуске приложения коллекция должна автоматически заполняться значениями из файла.
- Имя файла должно передаваться программе с помощью: переменная окружения.
- Данные должны храниться в файле в формате `xml`
- Чтение данных из файла необходимо реализовать с помощью класса `java.io.BufferedInputStream`
- Запись данных в файл необходимо реализовать с помощью класса `java.io.OutputStreamWriter`
- Все классы в программе должны быть задокументированы в формате javadoc.
- Программа должна корректно работать с неправильными данными (ошибки пользовательского ввода, отсутсвие прав доступа к файлу и т.п.).
В интерактивном режиме программа должна поддерживать выполнение следующих команд:
- `help` : вывести справку по доступным командам
- `info` : вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.)
- `show` : вывести в стандартный поток вывода все элементы коллекции в строковом представлении
- `add {element}` : добавить новый элемент в коллекцию
- `update id {element}` : обновить значение элемента коллекции, id которого равен заданному
- `remove_by_id id` : удалить элемент из коллекции по его id
- `clear` : очистить коллекцию
- `save` : сохранить коллекцию в файл
- `execute_script file_name` : считать и исполнить скрипт из указанного файла. В скрипте содержатся команды в таком же виде, в котором их вводит пользователь в интерактивном режиме.
- `exit` : завершить программу (без сохранения в файл)
- `add_if_max {element}` : добавить новый элемент в коллекцию, если его значение превышает значение наибольшего элемента этой коллекции
- `add_if_min {element}` : добавить новый элемент в коллекцию, если его значение меньше, чем у наименьшего элемента этой коллекции
- `remove_lower {element}` : удалить из коллекции все элементы, меньшие, чем заданный
- `filter_contains_name name` : вывести элементы, значение поля name которых содержит заданную подстроку
- `print_ascending` : вывести элементы коллекции в порядке возрастания
- `print_unique_manufacture_cost` : вывести уникальные значения поля manufactureCost всех элементов в коллекции
Формат ввода команд:
- Все аргументы команды, являющиеся стандартными типами данных (примитивные типы, классы-оболочки, String, классы для хранения дат), должны вводиться в той же строке, что и имя команды.
- Все составные типы данных (объекты классов, хранящиеся в коллекции) должны вводиться по одному полю в строку.
- При вводе составных типов данных пользователю должно показываться приглашение к вводу, содержащее имя поля (например, "Введите дату рождения:")
- Если поле является enum'ом, то вводится имя одной из его констант (при этом список констант должен быть предварительно выведен).
- При некорректном пользовательском вводе (введена строка, не являющаяся именем константы в enum'е; введена строка вместо числа; введённое число не входит в указанные границы и т.п.) должно быть показано сообщение об ошибке и предложено повторить ввод поля.
- Для ввода значений null использовать пустую строку.
- Поля с комментарием "Значение этого поля должно генерироваться автоматически" не должны вводиться пользователем вручную при добавлении.
Описание хранимых в коллекции классов:

1
db.xml
View File

@ -1 +0,0 @@
<Products><Product><id>341</id><name>ewreqr</name><coordinates><x>1432</x><y>132432</y></coordinates><creationDate>1711875600.000000000</creationDate><price>12324</price><partNumber>3214</partNumber><manufactureCost>342</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>324324</name><passportID>32143214</passportID><hairColor>WHITE</hairColor><location><x>342.0</x><y>423</y><name>214</name></location></owner></Product><Product><id>342</id><name>Hello</name><coordinates><x>13</x><y>4</y></coordinates><creationDate>1713267558.813808800</creationDate><price>12312</price><partNumber>312</partNumber><manufactureCost>321</manufactureCost><unitOfMeasure>CENTIMETERS</unitOfMeasure><owner><name>123</name><passportID>431</passportID><hairColor>BLACK</hairColor><location><x>2321.0</x><y>432</y><name>31</name></location></owner></Product></Products>

BIN
dml.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

62
nginx.conf Normal file
View File

@ -0,0 +1,62 @@
user nginx;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
#access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
map $http_upgrade $connection_upgrade {
default upgrade;
'' '';
}
server {
listen 80;
root /usr/share/nginx/html;
location / {
try_files $uri /index.html;
}
}
}

View File

@ -36,6 +36,11 @@
<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>
</dependencies>
<build>

View File

@ -25,7 +25,7 @@ public class Add extends Command {
var product = productCollection.addProduct(productDTO);
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
} catch (ValidationException e) {
throw new CommandActionException(e.getMessage());
throw new CommandActionException(String.format("Произошла ошибка при добавлении%n%s", e.getMessage()));
}
}
}

View File

@ -14,21 +14,26 @@ import java.util.regex.Pattern;
*/
public class AddIfMax extends Command {
public AddIfMax() {
super("add_if_max {element}", "добавить новый элемент в коллекцию, если его значение цены превышает значение наибольшей цены этой коллекции", Pattern.compile("^add_if_max \\d+"));
super("add_if_max {element}", "добавить новый элемент в коллекцию, если его значение цены превышает значение наибольшей цены этой коллекции", Pattern.compile("^add_if_max .+"));
}
@Override
public String action(ProductCollection productCollection) throws CommandActionException {
var productDTO = Console.readProductDTO();
try {
Validators.validateObject(productDTO).throwIfNotValid();
if (productCollection.getMaxPrice() < productDTO.getPrice()) {
var product = productCollection.addProduct(productDTO);
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
var productDTO = Console.readProductDTO();
try {
Validators.validateObject(productDTO).throwIfNotValid();
if (productCollection.getMaxPrice() == null ||productCollection.getMaxPrice() < productDTO.getPrice()) {
var product = productCollection.addProduct(productDTO);
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
}
return "Продукт не подходит под условие";
} catch (ValidationException e) {
throw new CommandActionException(e.getMessage());
}
return "Продукт не подходит под условие";
} catch (ValidationException e) {
throw new CommandActionException(e.getMessage());
} catch (NumberFormatException e) {
return "Неверный аргумент, id может быть только число";
}
}
}

View File

@ -19,16 +19,21 @@ public class AddIfMin extends Command {
@Override
public String action(ProductCollection productCollection) {
var productDTO = Console.readProductDTO();
try {
Validators.validateObject(productDTO).throwIfNotValid();
if (productCollection.getMinPrice() > productDTO.getPrice()) {
var product = productCollection.addProduct(productDTO);
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
Long.parseLong(Console.getLastCommand().split(" ")[1]);
var productDTO = Console.readProductDTO();
try {
Validators.validateObject(productDTO).throwIfNotValid();
if (productCollection.getMinPrice() == null || productCollection.getMinPrice() > productDTO.getPrice()) {
var product = productCollection.addProduct(productDTO);
return String.format("Продукт %s был добавлен под id %d", product.getName(), product.getId());
}
return "Продукт не подходит под условие";
} catch (ValidationException e) {
throw new CommandActionException(e.getMessage());
}
return "Продукт не подходит под условие";
} catch (ValidationException e) {
throw new CommandActionException(e.getMessage());
} catch (NumberFormatException e) {
return "Неверный аргумент, id может быть только число";
}
}
}

View File

@ -34,7 +34,9 @@ public class ExecuteScript extends Command {
@Override
public String action(ProductCollection productCollection) {
try {
var result = new StringBuilder();
var scriptFile = Console.getLastCommand().split(" ")[1];
result.append(String.format("Скрипт %s начинает работу.", scriptFile)).append("\n");
addFileToStack(scriptFile);
var commandList = ScriptLoader.loadList(scriptFile);
for (var input: commandList) {
@ -47,13 +49,14 @@ public class ExecuteScript extends Command {
if (checkFileInStack(nextFile)) continue;
addFileToStack(nextFile);
}
command.get().action(productCollection);
result.append(command.get().action(productCollection)).append("\n");
} else {
new UnknownCommand().action(productCollection);
}
}
clearStack();
return String.format("Скрипт %s завершил работу.%n", scriptFile);
result.append(String.format("Скрипт %s завершил работу.", scriptFile)).append("\n");
return result.toString();
} catch (IOException e) {
return e.getMessage();
}

View File

@ -13,7 +13,7 @@ public class Exit extends Command {
@Override
public String action(ProductCollection productCollection) {
Console.stopApp();
Console.stopAppWithoutSaving();
return "";
}
}

View File

@ -16,6 +16,7 @@ public class FilterContainsName extends Command {
@Override
public String action(ProductCollection productCollection) {
String name = Console.getLastCommand().split(" ")[1];
return productCollection.filterContainsName(name);
var result = productCollection.filterContainsName(name);
return result.isEmpty() ? "Таких элементов не найдено" : result;
}
}

View File

@ -12,6 +12,7 @@ public class PrintAscending extends Command {
@Override
public String action(ProductCollection productCollection) {
return productCollection.toString();
var result = productCollection.toString();
return result.isEmpty() ? "Коллекция пуста" : result;
}
}

View File

@ -12,6 +12,7 @@ public class PrintUniqueManufactureCost extends Command {
@Override
public String action(ProductCollection productCollection) {
return productCollection.getUniqueManufactureCost();
var result = productCollection.getUniqueManufactureCost();
return result.isEmpty() ? "Коллекция пуста" : result;
}
}

View File

@ -1,6 +1,7 @@
package me.zinch.commands;
import me.zinch.console.Console;
import me.zinch.exceptions.CommandActionException;
import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
@ -10,13 +11,20 @@ import java.util.regex.Pattern;
*/
public class Remove extends Command {
public Remove() {
super("remove_by_id id", "удалить элемент из коллекции по его id", Pattern.compile("^remove_by_id \\d+"));
super("remove_by_id id", "удалить элемент из коллекции по его id", Pattern.compile("^remove_by_id .+"));
}
@Override
public String action(ProductCollection productCollection) {
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
var product = productCollection.removeProduct(id);
return String.format("Продукт %s был удалён", product.getName());
public String action(ProductCollection productCollection) throws CommandActionException {
try {
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
if (productCollection.isProductIdExists(id)) {
var product = productCollection.removeProduct(id);
return String.format("Продукт %s был удалён", product.getName());
}
return "Продукта с таким id не существует";
} catch (NumberFormatException e) {
return "Неверный аргумент, id может быть только число";
}
}
}

View File

@ -15,8 +15,12 @@ public class RemoveLower extends Command {
@Override
public String action(ProductCollection productCollection) {
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
var size = productCollection.removeLover(id);
return String.format("Было удалено %d продуктов", size);
try {
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
var size = productCollection.removeLover(id);
return String.format("Было удалено %d продуктов", size);
} catch (NumberFormatException e) {
return "Неверный аргумент, id может быть только число";
}
}
}

View File

@ -12,6 +12,7 @@ public class Show extends Command {
@Override
public String action(ProductCollection productCollection) {
return productCollection.toString();
var result = productCollection.toString();
return result.isEmpty() ? "Коллекция пуста" : result;
}
}

View File

@ -13,22 +13,26 @@ import java.util.regex.Pattern;
*/
public class Update extends Command {
public Update() {
super("update id {element}", "обновить значение элемента коллекции, id которого равен заданному", Pattern.compile("^update \\d+"));
super("update id {element}", "обновить значение элемента коллекции, id которого равен заданному", Pattern.compile("^update .+"));
}
@Override
public String action(ProductCollection productCollection) throws CommandActionException {
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
if (productCollection.isProductIdExists(id)) {
var productDTO = Console.readProductDTO();
try {
Validators.validateObject(productDTO).throwIfNotValid();
var product = productCollection.updateProduct(id, productDTO);
return String.format("Продукт %s был изменён", product.getName());
} catch (ValidationException e) {
throw new CommandActionException(e.getMessage());
try {
Long id = Long.parseLong(Console.getLastCommand().split(" ")[1]);
if (productCollection.isProductIdExists(id)) {
var productDTO = Console.readProductDTO();
try {
Validators.validateObject(productDTO).throwIfNotValid();
var product = productCollection.updateProduct(id, productDTO);
return String.format("Продукт %s был изменён", product.getName());
} catch (ValidationException e) {
throw new CommandActionException(e.getMessage());
}
}
return "Продукта с таким id не существует";
} catch (NumberFormatException e) {
return "Неверный аргумент, id может быть только число";
}
return "Продукта с таким id не существует";
}
}

View File

@ -3,7 +3,6 @@ package me.zinch.console;
import me.zinch.commands.CommandManager;
import me.zinch.exceptions.ColorFormatException;
import me.zinch.exceptions.CommandActionException;
import me.zinch.exceptions.IllegalProductDtoException;
import me.zinch.exceptions.UnitOfMeasureFormatException;
import me.zinch.exceptions.ValidationException;
import me.zinch.files.DbController;
@ -11,6 +10,7 @@ import me.zinch.models.Color;
import me.zinch.models.Coordinates;
import me.zinch.models.Location;
import me.zinch.models.Person;
import me.zinch.models.Product;
import me.zinch.models.ProductDTO;
import me.zinch.models.UnitOfMeasure;
import me.zinch.validator.ValidateResult;
@ -19,9 +19,9 @@ import me.zinch.wrapper.ProductCollection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.IllegalFormatConversionException;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Scanner;
/**
@ -32,14 +32,39 @@ public class Console {
private static final Scanner scanner = new Scanner(System.in);
private static boolean isRunning = true;
private static final List<String> history = new ArrayList<>();
private static boolean isExitMessageShowed = false;
private static ProductCollection productCollection;
public static void appendHistory(String input) {
history.add(input);
}
public static void stopApp() {
public static void log(String msg) {
if (isRunning) System.out.println(msg);
}
public static void log() {
log("");
}
public static void stopAppWithoutSaving() {
showExitMessage();
isRunning = false;
scanner.close();
}
public static void stopAppWithSaving() {
try {
DbController.saveDb(productCollection.toList());
} catch (IOException e) {
log(e.getMessage());
}
stopAppWithoutSaving();
}
public static void showExitMessage() {
if (!isExitMessageShowed) log("\nВсего хорошего!");
isExitMessageShowed = true;
}
public static String getLastCommand() {
@ -48,16 +73,18 @@ public class Console {
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 = scanner.nextLine().trim();
var input = readString();
if (input == null || input.isEmpty()) return null;
try {
return Long.parseLong(input);
} catch (NumberFormatException e) {
return null;
throw new NumberFormatException(String.format("Не могу распознать %s как число", input));
}
}
@ -103,69 +130,100 @@ public class Console {
return new Location(locationX, locationY, locationName);
}
public static ProductDTO readProductDTO() throws IllegalProductDtoException {
try {
var productDTO = new ProductDTO();
System.out.println("Заполните следующие поля: ");
System.out.print("Название: ");
productDTO.setName(readString());
System.out.print("Координата x: ");
long x = readLong();
System.out.print("Координата y: ");
long y = readLong();
productDTO.setCoordinates(new Coordinates(x, y));
System.out.print("Цена: ");
productDTO.setPrice(readLong());
System.out.print("Номер части: ");
productDTO.setPartNumber(readString());
System.out.print("Себестоимость: ");
productDTO.setManufactureCost(readLong());
productDTO.setUnitOfMeasure(readUnitOfMeasure());
System.out.print("Имя владельца: ");
var ownerName = readString();
System.out.print("Данные паспорта: ");
var passportId = readString();
Color color = readColor();
productDTO.setOwner(new Person(ownerName, passportId, color, readLocation()));
return productDTO;
} catch (ColorFormatException | UnitOfMeasureFormatException e) {
throw new IllegalProductDtoException(e.getMessage());
} catch (NumberFormatException | NullPointerException | IllegalFormatConversionException e) {
throw new IllegalProductDtoException();
private static String readPartNumber() throws IllegalArgumentException {
var partNumber = readString();
var partNumbers = productCollection.toList()
.stream()
.map(Product::getPartNumber)
.filter(Objects::nonNull)
.filter(s -> s.equals(partNumber))
.toList();
if (!partNumbers.isEmpty()) {
throw new IllegalArgumentException("Поле partNumber должно быть уникальным");
}
return partNumber;
}
private static void readField(String fieldName, Runnable function) {
while (isRunning) {
if (fieldName != null) System.out.format("%s: ", fieldName);
try {
function.run();
return;
} catch (NullPointerException e) {
log("Произошла ошибка при заполнении поля\оле не может быть пустым");
} catch (Exception e) {
System.out.format("Произошла ошибка при заполнении поля%n%s%n", e.getMessage());
}
}
}
private static void readField(Runnable function) {
readField(null, function);
}
public static ProductDTO readProductDTO() {
var productDTO = new ProductDTO();
var coordinates = new Coordinates();
var owner = new Person();
log("Заполните следующие поля: ");
readField("Название [не может быть пустым]", () -> productDTO.setName(readString()));
readField("Координата x [должна быть меньше 884]", () -> coordinates.setX(readLong()));
readField("Координата y [должна быть больше -427, не может быть пустой]", () -> coordinates.setY(readLong()));
readField("Цена [должна быть больше 0, не может быть пустой]", () -> productDTO.setPrice(readLong()));
readField("Номер части [не больше 82 символов, должен быть уникальным]", () -> productDTO.setPartNumber(readPartNumber()));
readField("Себестоимость [не может быть пустым]", () -> productDTO.setManufactureCost(readLong()));
readField(() -> productDTO.setUnitOfMeasure(readUnitOfMeasure()));
readField("Имя владельца [не может быть пустым]", () -> owner.setName(readString()));
readField("Данные паспорта [длина строки от 5 до 22, не может быть пустым]", () -> owner.setPassportID(readString()));
readField(() -> owner.setHairColor(readColor()));
readField(() -> owner.setLocation(readLocation()));
productDTO.setCoordinates(coordinates);
productDTO.setOwner(owner);
return productDTO;
}
public static void run() throws IOException, ValidationException {
var productList = DbController.loadDb();
var validationResult = Validators.validateProductList(productList);
if (!validationResult.stream().allMatch(ValidateResult::isValid)) {
throw new ValidationException(String.join("\n", validationResult
.stream()
.map(ValidateResult::getMessage)
.toList()));
}
var productCollection = new ProductCollection(productList);
System.out.println("Добро пожаловать! Для просмотра команд введите help");
if (productList.isEmpty()) log("Коллекция путая\n");
productCollection = new ProductCollection(productList);
log("Добро пожаловать! Для просмотра команд введите help");
while(isRunning) {
System.out.print(":");
try {
var input = scanner.nextLine().trim();
var command = CommandManager.getCommandByInput(input);
if (command.isPresent()) {
appendHistory(input);
try {
System.out.println(command.get().action(productCollection));
log(command.get().action(productCollection));
} catch (CommandActionException e) {
System.out.println(e.getMessage());
log(e.getMessage());
}
} else {
System.out.println("Такой команды не существует. Напишите help, чтобы посмотреть список доступных команд.");
log("Такой команды не существует. Напишите help, чтобы посмотреть список доступных команд.");
}
} catch (NoSuchElementException e) {
stopApp();
stopAppWithoutSaving();
}
System.out.println();
log();
}
System.out.println("Всего хорошего!");
scanner.close();
}
}

View File

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

View File

@ -9,4 +9,8 @@ public class DbInitializationException extends IOException {
public DbInitializationException() {
super("Ошибка! Не удалось инициализировать БД. Проверьте, что структура БД верна.");
}
public DbInitializationException(String message) {
super(message);
}
}

View File

@ -1,20 +1,18 @@
package me.zinch.files;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import me.zinch.exceptions.DbInitializationException;
import me.zinch.models.Product;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -53,15 +51,12 @@ public class DbController {
public static List<Product> loadDb() throws IOException {
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));
Products collection = xmlMapper.readValue(bufferedInputStream, Products.class);
List<Product> collection = xmlMapper.readValue(bufferedInputStream, Products.class).getProducts();
bufferedInputStream.close();
return collection.getProducts();
} catch (FileNotFoundException e) {
throw new FileNotFoundException("Не удалось найти файл " + path);
} catch (DatabindException e) {
throw new DbInitializationException();
if (collection == null) return new ArrayList<>();
return collection;
} catch (IOException e) {
throw new IOException("Произошла неожиданная ошибка во время работы с файлом!");
return new ArrayList<>();
}
}
@ -70,10 +65,8 @@ public class DbController {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(path));
xmlMapper.writeValue(outputStreamWriter, new Products(list));
outputStreamWriter.close();
} catch (FileNotFoundException e) {
throw new FileNotFoundException(e.getMessage());
} catch (IOException e) {
throw new IOException(e);
throw new IOException("Не удалось записать в файл");
}
}
}

View File

@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import me.zinch.exceptions.ValidationException;
import java.util.Objects;
@ -15,7 +16,7 @@ public class Coordinates {
@JsonProperty("x")
private long x; //Максимальное значение поля: 883
@NotNull(message = "Coordinates: Поле не может быть null")
@NotNull(message = "Coordinates: Поле y не может быть null")
@Min(value = -427, message = "Значение координаты y должно быть больше -427")
@JsonProperty("y")
private Long y; //Значение поля должно быть больше -427, Поле не может быть null
@ -27,6 +28,17 @@ public class Coordinates {
this.y = y;
}
public void setX(long x) {
if (x > 883) throw new ValidationException("Максимальное значение координаты x: 883");
this.x = x;
}
public void setY(Long y) {
if (y == null) throw new ValidationException("Поле y не может быть null");
if (y < -427) throw new ValidationException("Значение координаты y должно быть больше -427");
this.y = y;
}
@Override
public String toString() {
return "Coordinates{" +

View File

@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import me.zinch.exceptions.ValidationException;
import java.util.Objects;
@ -36,10 +37,13 @@ public class Person {
}
public void setName(String name) {
if (name == null || name.isEmpty()) throw new ValidationException("Имя персоны не может быть пустым или null");
this.name = name;
}
public void setPassportID(String passportID) {
if (passportID == null) throw new ValidationException("Поле passportID не может быть null");
if (passportID.length() < 5 || passportID.length() > 22) throw new ValidationException("Длина строки passportID должна быть не меньше 5 и не должна быть больше 22");
this.passportID = passportID;
}

View File

@ -6,6 +6,7 @@ import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import me.zinch.exceptions.ValidationException;
import me.zinch.validator.NotEmpty;
@ -24,7 +25,7 @@ public class ProductDTO {
private Coordinates coordinates; //Поле не может быть null
@NotNull(message = "ProductDTO: Поле price не может быть null")
@Min(value = 1, message = "Поле price не может быть null")
@Min(value = 1, message = "ProductDTO: Значение поля price должно быть больше 0")
@JsonProperty("price")
private Long price; //Поле не может быть null, Значение поля должно быть больше 0
@ -97,18 +98,24 @@ public class ProductDTO {
}
public void setName(String name) {
if (name == null || name.isEmpty()) throw new ValidationException("Строка name не может быть пустой или null");
this.name = name;
}
public void setCoordinates(Coordinates coordinates) {
if (coordinates == null) throw new ValidationException("Поле coordinates не может быть null");
this.coordinates = coordinates;
}
public void setPrice(Long price) {
if (price == null) throw new ValidationException("Поле price не может быть null");
if (price <= 0) throw new ValidationException("Поле price не может быть null");
this.price = price;
}
public void setPartNumber(String partNumber) {
if (partNumber.isEmpty()) throw new ValidationException("Строка partNumber не может быть пустой");
if (partNumber.length() > 82) throw new ValidationException("Длина строки partNumber не должна быть больше 82");
this.partNumber = partNumber;
}
@ -117,10 +124,12 @@ public class ProductDTO {
}
public void setUnitOfMeasure(UnitOfMeasure unitOfMeasure) {
if (unitOfMeasure == null) throw new ValidationException("Поле unitOfMeasure не может быть null");
this.unitOfMeasure = unitOfMeasure;
}
public void setOwner(Person owner) {
if (owner == null) throw new ValidationException("Поле owner не может быть null");
this.owner = owner;
}
}

View File

@ -1,7 +1,7 @@
package me.zinch.validator;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ValidationException;
import me.zinch.exceptions.ValidationException;
import java.util.Set;

View File

@ -7,6 +7,7 @@ import me.zinch.models.Product;
import org.hibernate.validator.HibernateValidator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
@ -30,7 +31,7 @@ public class Validators {
public static List<ValidateResult<Product>> validateProductList(List<Product> db) {
var ids = db.stream().map(Product::getId).toList();
var partNumbers = db.stream().map(Product::getPartNumber).toList();
var partNumbers = db.stream().map(Product::getPartNumber).filter(Objects::nonNull).toList();
var validations = new java.util.ArrayList<>(db.stream().map(Validators::validateObject).toList());
if (ids.size() != Set.copyOf(ids).size()) {
validations.add(new ValidateResult<>("Поле id должно быть уникальным"));

View File

@ -24,7 +24,7 @@ public class ProductCollection {
public ProductCollection(List<Product> list) throws ValidationException {
productList = new TreeSet<>(Comparator.comparingLong(Product::getId));
productList.addAll(list);
idIncrementor = productList.last().getId() + 1;
idIncrementor = productList.isEmpty() ? 1L : productList.last().getId() + 1;
}
private Long generateId() {
@ -63,7 +63,7 @@ public class ProductCollection {
public String getInfo() {
var optionalInitDate = productList.stream().map(Product::getCreationDate).sorted().findFirst();
ZonedDateTime initDate = optionalInitDate.orElse(ZonedDateTime.ofInstant(Instant.EPOCH, ZoneId.systemDefault()));
return String.format("TreeSet%nInit Date: %s%nNumber of elements: %s", initDate, productList.size());
return String.format("Структура: TreeSet%nДата инициализации: %s%nКоличество элементов: %s", initDate, productList.size());
}
public void clear() {