Merge branch 'lab5-dev' into develop

This commit is contained in:
Ivan Zinchenko 2024-04-03 10:44:39 +03:00
commit 4e08255632
Signed by: zinch
GPG Key ID: 6D45AA2C8FD6A37E
42 changed files with 235 additions and 4 deletions

View File

@ -1,4 +0,0 @@
### Этапы работы программы
1. Проверка файла с базой данных
2. Пользовательский ввод

View File

@ -64,6 +64,11 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
</plugin>
</plugins>
</build>
</project>

View File

@ -6,6 +6,9 @@ import me.zinch.exceptions.ValidationException;
import java.io.IOException;
/**
* Main class for running the application.
*/
public class App {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new ShutdownHook());

View File

@ -6,6 +6,10 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* The Add class represents a command to add a new element to a collection.
* It extends the Command class.
*/
public class Add extends Command {
public Add() {
super("add {element}", "добавить новый элемент в коллекцию", Pattern.compile("^add"));

View File

@ -5,6 +5,10 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* The AddIfMax class represents a command to add a new element to a collection if its price value exceeds the maximum price value in the collection.
* It extends the Command class.
*/
public class AddIfMax extends Command {
public AddIfMax() {
super("add_if_max {element}", "добавить новый элемент в коллекцию, если его значение цены превышает значение наибольшей цены этой коллекции", Pattern.compile("^add_if_max \\d+"));

View File

@ -5,6 +5,10 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* The AddIfMin class represents a command to add a new element to a collection if its price is lower than the lowest price in the collection.
* It extends the Command class.
*/
public class AddIfMin extends Command {
public AddIfMin() {
super("add_if_min {element}", "добавить новый элемент в коллекцию, если его значение цены меньше, чем у наименьшей цены этой коллекции", Pattern.compile("^add_if_min \\d+"));

View File

@ -2,6 +2,10 @@ package me.zinch.commands;
import me.zinch.wrapper.ProductCollection;
/**
* The Clear class represents a command to clear a collection.
* It extends the Command class.
*/
public class Clear extends Command {
public Clear() {
super("clear", "очистить коллекцию");

View File

@ -5,6 +5,9 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* Represents a command that can be executed.
*/
public abstract class Command {
private final String name;
private final String description;

View File

@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* Manages the registration and retrieval of commands.
*/
public class CommandManager {
private static final List<Command> commandList = new ArrayList<>();

View File

@ -0,0 +1,61 @@
package me.zinch.commands;
import me.zinch.console.Console;
import me.zinch.files.ScriptLoader;
import me.zinch.wrapper.ProductCollection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* A command to execute a script from a specified file.
*/
public class ExecuteScript extends Command {
private static final List<String> executeStack = new ArrayList<>();
private void addFileToStack(String filePath) {
executeStack.add(filePath);
}
private void clearStack() {
executeStack.clear();
}
private boolean checkFileInStack(String filePath) {
return executeStack.contains(filePath);
}
public ExecuteScript() {
super("execute_script file_name", "считать и исполнить скрипт из указанного файла. В скрипте содержатся команды в таком же виде, в котором их вводит пользователь в интерактивном режиме", Pattern.compile("^execute_script .+"));
}
@Override
public void action(ProductCollection productCollection) {
try {
var scriptFile = Console.getLastCommand().split(" ")[1];
addFileToStack(scriptFile);
var commandList = ScriptLoader.loadList(scriptFile);
for (var input: commandList) {
input = input.trim();
var command = CommandManager.getCommandByInput(input);
if (command.isPresent()) {
Console.appendHistory(input);
if (command.get() instanceof ExecuteScript) {
var nextFile = input.split(" ")[0];
if (checkFileInStack(nextFile)) continue;
addFileToStack(nextFile);
}
command.get().action(productCollection);
} else {
new UnknownCommand().action(productCollection);
}
}
clearStack();
System.out.format("Скрипт %s завершил работу.%n", scriptFile);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}

View File

@ -3,6 +3,9 @@ package me.zinch.commands;
import me.zinch.console.Console;
import me.zinch.wrapper.ProductCollection;
/**
* A command to exit the program without saving to a file.
*/
public class Exit extends Command {
public Exit() {
super("exit", "завершить программу (без сохранения в файл)");

View File

@ -5,6 +5,9 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* A command to filter elements whose 'name' field contains the specified substring.
*/
public class FilterContainsName extends Command {
public FilterContainsName() {
super("filter_contains_name name", "вывести элементы, значение поля name которых содержит заданную подстроку", Pattern.compile("^filter_contains_name \\w+"));

View File

@ -2,6 +2,9 @@ package me.zinch.commands;
import me.zinch.wrapper.ProductCollection;
/**
* A command to display help for available commands.
*/
public class Help extends Command {
public Help() {
super("help", "вывести справку по доступным командам");

View File

@ -2,6 +2,9 @@ package me.zinch.commands;
import me.zinch.wrapper.ProductCollection;
/**
* A command to display information about the collection (type, initialization date, number of elements, etc.) to the standard output stream.
*/
public class Info extends Command {
public Info() {
super("info", "вывести в стандартный поток вывода информацию о коллекции (тип, дата инициализации, количество элементов и т.д.)");

View File

@ -2,6 +2,9 @@ package me.zinch.commands;
import me.zinch.wrapper.ProductCollection;
/**
* A command to print the elements of the collection in ascending order.
*/
public class PrintAscending extends Command {
public PrintAscending() {
super("print_ascending", "вывести элементы коллекции в порядке возрастания");

View File

@ -2,6 +2,9 @@ package me.zinch.commands;
import me.zinch.wrapper.ProductCollection;
/**
* A command to print the unique values of the 'manufactureCost' field of all elements in the collection.
*/
public class PrintUniqueManufactureCost extends Command {
public PrintUniqueManufactureCost() {
super("print_unique_manufacture_cost", "вывести уникальные значения поля manufactureCost всех элементов в коллекции");

View File

@ -5,6 +5,9 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* A command to remove an element from the collection by its id.
*/
public class Remove extends Command {
public Remove() {
super("remove_by_id id", "удалить элемент из коллекции по его id", Pattern.compile("^remove_by_id \\d+"));

View File

@ -5,6 +5,9 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* A command to remove all elements from the collection that have ids lower than the specified id.
*/
public class RemoveLower extends Command {
public RemoveLower() {
super("remove_lower id", "удалить из коллекции все элементы, меньшие, чем заданный по id", Pattern.compile("^remove_lower \\d+"));

View File

@ -6,6 +6,9 @@ import me.zinch.wrapper.ProductCollection;
import java.io.IOException;
/**
* A command to save the collection to a file.
*/
public class Save extends Command {
public Save() {
super("save", "сохранить коллекцию в файл");

View File

@ -2,6 +2,9 @@ package me.zinch.commands;
import me.zinch.wrapper.ProductCollection;
/**
* A command to display all elements of the collection in string representation to the standard output stream.
*/
public class Show extends Command {
public Show() {
super("show", "вывести в стандартный поток вывода все элементы коллекции в строковом представлении");

View File

@ -0,0 +1,17 @@
package me.zinch.commands;
import me.zinch.wrapper.ProductCollection;
/**
* Represents an unknown command.
*/
public class UnknownCommand extends Command {
public UnknownCommand() {
super("", "");
}
@Override
public void action(ProductCollection productCollection) {
System.out.println("Команда не распознана.");
}
}

View File

@ -5,6 +5,9 @@ import me.zinch.wrapper.ProductCollection;
import java.util.regex.Pattern;
/**
* A command to update the value of an element in the collection, whose id is specified.
*/
public class Update extends Command {
public Update() {
super("update id {element}", "обновить значение элемента коллекции, id которого равен заданному", Pattern.compile("^update \\d+"));

View File

@ -18,6 +18,10 @@ import java.util.List;
import java.util.NoSuchElementException;
import java.util.Scanner;
/**
Console class provides methods for interacting with the console, reading user input, and managing application flow.
This class includes methods for appending input history, stopping the application, reading product DTO from the console, and running the application loop.
*/
public class Console {
private static final Scanner scanner = new Scanner(System.in);
private static boolean isRunning = true;

View File

@ -1,5 +1,8 @@
package me.zinch.console;
/**
* Represents a shutdown hook that is executed when the application is stopped.
*/
public class ShutdownHook extends Thread {
public ShutdownHook() {
super(new Thread(Console::stopApp));

View File

@ -1,5 +1,8 @@
package me.zinch.exceptions;
/**
* Represents an exception that occurs during the execution of a command action.
*/
public class CommandActionException extends RuntimeException {
public CommandActionException() {
super("Ошибка во время выполнения команды");

View File

@ -2,6 +2,9 @@ package me.zinch.exceptions;
import java.io.IOException;
/**
* Represents an exception that occurs when the database initialization fails.
*/
public class DbInitializationException extends IOException {
public DbInitializationException() {
super("Ошибка! Не удалось инициализировать БД. Проверьте, что структура БД верна.");

View File

@ -1,5 +1,8 @@
package me.zinch.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("Ошибка при создании или изменении продукта. Были введены некорректные значения.");

View File

@ -1,5 +1,8 @@
package me.zinch.exceptions;
/**
* Represents an exception related to validation errors.
*/
public class ValidationException extends jakarta.validation.ValidationException {
public ValidationException() {}

View File

@ -18,6 +18,9 @@ import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;
/**
* The DbController class provides methods for loading and saving product data to a database file.
*/
public class DbController {
private static final XmlMapper xmlMapper = XmlMapper.builder().addModule(new JavaTimeModule()).build();
private static final String path;
@ -28,6 +31,9 @@ public class DbController {
xmlMapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);
}
/**
* Represents a collection of products.
*/
private static class Products {
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "Product")

View File

@ -0,0 +1,32 @@
package me.zinch.files;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* The ScriptLoader class provides methods to load scripts from files.
*/
public class ScriptLoader {
public static List<String> loadList(String path) throws IOException {
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));
Scanner scanner = new Scanner(bufferedInputStream);
List<String> list = new ArrayList<>();
while (scanner.hasNextLine()) {
list.add(scanner.nextLine());
}
bufferedInputStream.close();
scanner.close();
return list;
} catch (FileNotFoundException e) {
throw new FileNotFoundException(String.format("Файл %s не найден.", path));
} catch (IOException e) {
throw new IOException("Произошла неожиданная ошибка во время работы с файлом!");
}
}
}

View File

@ -2,6 +2,9 @@ package me.zinch.models;
import java.util.List;
/**
* Represents a color enumeration.
*/
public enum Color {
GREEN("Зелёный"),
BLACK("Чёрный"),

View File

@ -7,6 +7,9 @@ import jakarta.validation.constraints.NotNull;
import java.util.Objects;
/**
* Represents coordinates with x and y values.
*/
public class Coordinates {
@Max(value = 883, message = "Coordinates: Максимальное значение координаты x: 883")
@JsonProperty("x")

View File

@ -6,6 +6,9 @@ import me.zinch.validator.NotEmpty;
import java.util.Objects;
/**
* Represents a location with x and y coordinates and a name.
*/
public class Location {
@JsonProperty("x")
private float x;

View File

@ -7,6 +7,9 @@ import jakarta.validation.constraints.Size;
import java.util.Objects;
/**
* Represents a person with a name, passport ID, hair color, and location.
*/
public class Person {
@NotBlank(message = "Person: Имя персоны не может быть пустым или null")
@JsonProperty("name")

View File

@ -10,6 +10,9 @@ import me.zinch.validator.NotEmpty;
import java.time.ZonedDateTime;
import java.util.Objects;
/**
* Represents a product with various attributes such as ID, name, coordinates, creation date, price, part number, manufacture cost, unit of measure, and owner.
*/
public class Product {
@NotNull(message = "Product: Поле id не может быть null")
@Min(value = 1, message = "Product: Значение поля id должно быть больше 0")

View File

@ -11,6 +11,9 @@ import me.zinch.validator.NotEmpty;
import java.time.ZonedDateTime;
/**
* Represents a Data Transfer Object (DTO) for a product with attributes such as name, coordinates, price, part number, manufacture cost, unit of measure, and owner.
*/
public class ProductDTO {
@NotBlank(message = "Строка name не может быть пустой или null")
@JsonProperty("name")

View File

@ -2,6 +2,9 @@ package me.zinch.models;
import java.util.List;
/**
* Represents a unit of measure enumeration.
*/
public enum UnitOfMeasure {
KILOGRAMS("Килограммы"),
CENTIMETERS("Сантиметры"),

View File

@ -8,6 +8,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation indicating that the annotated element must not be empty.
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NotEmptyValidator.class)

View File

@ -3,6 +3,9 @@ package me.zinch.validator;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* Validator implementation for the {@link NotEmpty} annotation, ensuring that the value is not empty.
*/
public class NotEmptyValidator implements ConstraintValidator<NotEmpty, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {

View File

@ -5,6 +5,10 @@ import jakarta.validation.ValidationException;
import java.util.Set;
/**
* Represents the result of a validation process.
* @param <T> the type of object being validated
*/
public class ValidateResult<T> {
private final Set<ConstraintViolation<T>> violations;
private final boolean isValid;

View File

@ -8,6 +8,9 @@ import org.hibernate.validator.HibernateValidator;
import java.util.List;
/**
* Utility class for performing validation operations on products.
*/
public class Validators {
private static final Validator validator;

View File

@ -16,6 +16,9 @@ import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
/**
* Represents a collection of products.
*/
public class ProductCollection {
private final TreeSet<Product> productList;
private Long idIncrementor;