From 1e2e24615ea078750bb821d6a232e7d68a647a0b Mon Sep 17 00:00:00 2001 From: stvort Date: Fri, 3 Feb 2023 23:09:48 +0400 Subject: [PATCH] 2023-01 spring-03-arch added --- 2023-01/spring-03-arch/.gitignore | 4 + 2023-01/spring-03-arch/pom.xml | 25 ++++ 2023-01/spring-03-arch/solution01/.gitignore | 4 + 2023-01/spring-03-arch/solution01/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 65 +++++++++ .../solution02_codeface/.gitignore | 4 + .../solution02_codeface/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 79 +++++++++++ .../spring-03-arch/solution03_kiss/.gitignore | 4 + .../spring-03-arch/solution03_kiss/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 104 ++++++++++++++ .../spring-03-arch/solution04_kiss/.gitignore | 4 + .../spring-03-arch/solution04_kiss/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 107 +++++++++++++++ .../spring-03-arch/solution05_dry/.gitignore | 4 + 2023-01/spring-03-arch/solution05_dry/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 118 ++++++++++++++++ .../spring-03-arch/solution06_dry/.gitignore | 4 + 2023-01/spring-03-arch/solution06_dry/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 127 ++++++++++++++++++ .../MenuItemIndexOutOfBoundsException.java | 7 + .../NoteIndexOutOfBoundsException.java | 7 + .../spring-03-arch/solution07_srp/.gitignore | 4 + 2023-01/spring-03-arch/solution07_srp/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 109 +++++++++++++++ .../MenuItemIndexOutOfBoundsException.java | 7 + .../NoteIndexOutOfBoundsException.java | 7 + .../src/main/java/ru/otus/model/Note.java | 26 ++++ .../ru/otus/services/ConsoleIOService.java | 29 ++++ .../java/ru/otus/services/NoteConverter.java | 9 ++ .../spring-03-arch/solution08_srp/.gitignore | 4 + 2023-01/spring-03-arch/solution08_srp/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 10 ++ .../MenuItemIndexOutOfBoundsException.java | 7 + .../NoteIndexOutOfBoundsException.java | 7 + .../src/main/java/ru/otus/model/Note.java | 53 ++++++++ .../ru/otus/services/ApplicationRunner.java | 72 ++++++++++ .../ru/otus/services/ConsoleIOService.java | 29 ++++ .../otus/services/MenuCommandsProcessor.java | 58 ++++++++ .../java/ru/otus/services/NoteConverter.java | 9 ++ .../java/ru/otus/services/NotesService.java | 26 ++++ .../spring-03-arch/solution09_dip/.gitignore | 4 + 2023-01/spring-03-arch/solution09_dip/pom.xml | 23 ++++ .../src/main/java/ru/otus/Main.java | 20 +++ .../main/java/ru/otus/config/AppSettings.java | 19 +++ .../MenuItemIndexOutOfBoundsException.java | 7 + .../NoteIndexOutOfBoundsException.java | 7 + .../src/main/java/ru/otus/model/Note.java | 53 ++++++++ .../ru/otus/services/ApplicationRunner.java | 71 ++++++++++ .../otus/services/ApplicationStopService.java | 6 + .../services/ApplicationStopServiceImpl.java | 34 +++++ .../main/java/ru/otus/services/IOService.java | 11 ++ .../ru/otus/services/IOServiceStreams.java | 37 +++++ .../otus/services/MenuCommandsProcessor.java | 13 ++ .../services/MenuCommandsProcessorImpl.java | 74 ++++++++++ .../java/ru/otus/services/NoteConverter.java | 7 + .../ru/otus/services/NoteConverterImpl.java | 21 +++ .../java/ru/otus/services/NotesService.java | 13 ++ .../ru/otus/services/NotesServiceImpl.java | 31 +++++ .../solution10_ocp_isp/.gitignore | 4 + .../spring-03-arch/solution10_ocp_isp/pom.xml | 69 ++++++++++ .../src/main/java/ru/otus/Main.java | 46 +++++++ .../main/java/ru/otus/config/AppSettings.java | 21 +++ ...pplicationStopServiceSettingsProvider.java | 5 + .../otus/config/DateTimeFormatProvider.java | 5 + .../MenuCommandProcessorNotFound.java | 7 + .../MenuItemIndexOutOfBoundsException.java | 7 + .../NoteIndexOutOfBoundsException.java | 7 + .../src/main/java/ru/otus/model/Note.java | 53 ++++++++ .../ru/otus/services/ApplicationRunner.java | 66 +++++++++ .../otus/services/ApplicationStopService.java | 6 + .../services/ApplicationStopServiceImpl.java | 36 +++++ .../main/java/ru/otus/services/IOService.java | 9 ++ .../ru/otus/services/IOServiceStreams.java | 37 +++++ .../java/ru/otus/services/NoteConverter.java | 7 + .../ru/otus/services/NoteConverterImpl.java | 20 +++ .../java/ru/otus/services/NotesService.java | 13 ++ .../ru/otus/services/NotesServiceImpl.java | 31 +++++ .../ru/otus/services/menu/MenuOption.java | 34 +++++ .../services/menu/MenuOptionsRegistry.java | 9 ++ .../menu/MenuOptionsRegistryImpl.java | 26 ++++ .../AddNewNoteSingleCommandProcessor.java | 30 +++++ .../DeleteNoteSingleCommandProcessor.java | 37 +++++ .../services/processors/InputService.java | 9 ++ .../processors/MenuCommandsProcessor.java | 7 + .../processors/MenuCommandsProcessorImpl.java | 27 ++++ .../MenuSingleCommandProcessor.java | 8 ++ .../services/processors/OutputService.java | 5 + .../ShowAllNotesSingleCommandProcessor.java | 38 ++++++ ...StopApplicationSingleCommandProcessor.java | 25 ++++ .../UpdateNoteSingleCommandProcessor.java | 41 ++++++ .../processors/utils/NotesListUtil.java | 11 ++ .../ApplicationStopServiceImplTest.java | 33 +++++ .../menu/MenuOptionsRegistryImplTest.java | 44 ++++++ .../AddNewNoteSingleCommandProcessorTest.java | 59 ++++++++ .../MenuCommandsProcessorImplTest.java | 55 ++++++++ 96 files changed, 2715 insertions(+) create mode 100644 2023-01/spring-03-arch/.gitignore create mode 100644 2023-01/spring-03-arch/pom.xml create mode 100644 2023-01/spring-03-arch/solution01/.gitignore create mode 100644 2023-01/spring-03-arch/solution01/pom.xml create mode 100644 2023-01/spring-03-arch/solution01/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution02_codeface/.gitignore create mode 100644 2023-01/spring-03-arch/solution02_codeface/pom.xml create mode 100644 2023-01/spring-03-arch/solution02_codeface/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution03_kiss/.gitignore create mode 100644 2023-01/spring-03-arch/solution03_kiss/pom.xml create mode 100644 2023-01/spring-03-arch/solution03_kiss/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution04_kiss/.gitignore create mode 100644 2023-01/spring-03-arch/solution04_kiss/pom.xml create mode 100644 2023-01/spring-03-arch/solution04_kiss/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution05_dry/.gitignore create mode 100644 2023-01/spring-03-arch/solution05_dry/pom.xml create mode 100644 2023-01/spring-03-arch/solution05_dry/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution06_dry/.gitignore create mode 100644 2023-01/spring-03-arch/solution06_dry/pom.xml create mode 100644 2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution07_srp/.gitignore create mode 100644 2023-01/spring-03-arch/solution07_srp/pom.xml create mode 100644 2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/model/Note.java create mode 100644 2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/ConsoleIOService.java create mode 100644 2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/NoteConverter.java create mode 100644 2023-01/spring-03-arch/solution08_srp/.gitignore create mode 100644 2023-01/spring-03-arch/solution08_srp/pom.xml create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/model/Note.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ApplicationRunner.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ConsoleIOService.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/MenuCommandsProcessor.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NoteConverter.java create mode 100644 2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NotesService.java create mode 100644 2023-01/spring-03-arch/solution09_dip/.gitignore create mode 100644 2023-01/spring-03-arch/solution09_dip/pom.xml create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/config/AppSettings.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/model/Note.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationRunner.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopService.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOService.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOServiceStreams.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessor.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessorImpl.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverter.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverterImpl.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesService.java create mode 100644 2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesServiceImpl.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/.gitignore create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/pom.xml create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/Main.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/AppSettings.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/ApplicationStopServiceSettingsProvider.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/DateTimeFormatProvider.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuCommandProcessorNotFound.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/model/Note.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationRunner.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopService.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOService.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOServiceStreams.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverter.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverterImpl.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesService.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesServiceImpl.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOption.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistry.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistryImpl.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessor.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/DeleteNoteSingleCommandProcessor.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/InputService.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessor.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessorImpl.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuSingleCommandProcessor.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/OutputService.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/ShowAllNotesSingleCommandProcessor.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/StopApplicationSingleCommandProcessor.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/UpdateNoteSingleCommandProcessor.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/utils/NotesListUtil.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/ApplicationStopServiceImplTest.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/menu/MenuOptionsRegistryImplTest.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessorTest.java create mode 100644 2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/MenuCommandsProcessorImplTest.java diff --git a/2023-01/spring-03-arch/.gitignore b/2023-01/spring-03-arch/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/pom.xml b/2023-01/spring-03-arch/pom.xml new file mode 100644 index 00000000..0890067c --- /dev/null +++ b/2023-01/spring-03-arch/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + ru.otus + architecture-origins + 1.0 + + pom + + + solution01 + solution02_codeface + solution03_kiss + solution04_kiss + solution05_dry + solution06_dry + solution07_srp + solution08_srp + solution09_dip + solution10_ocp_isp + + diff --git a/2023-01/spring-03-arch/solution01/.gitignore b/2023-01/spring-03-arch/solution01/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution01/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution01/pom.xml b/2023-01/spring-03-arch/solution01/pom.xml new file mode 100644 index 00000000..b7708bca --- /dev/null +++ b/2023-01/spring-03-arch/solution01/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution01 + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution01/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution01/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..4ccd71f4 --- /dev/null +++ b/2023-01/spring-03-arch/solution01/src/main/java/ru/otus/Main.java @@ -0,0 +1,65 @@ +package ru.otus; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.stream.IntStream; + +public class Main { + + public static void main(String[] args) { + List strings = new ArrayList<>(); + Scanner sc = new Scanner(System.in); + + while (true) { + System.out.println("Выберите одно из следующих действий..."); + System.out.println("1. Вывести все заметки"); + System.out.println("2. Добавить заметку"); + System.out.println("3. Изменить заметку"); + System.out.println("4. Удалить заметку"); + System.out.println("5. Выйти"); + + try { + int i = Integer.parseInt(sc.nextLine()); + + if (i == 1) { + System.out.println("Заметки:"); + IntStream.range(1, strings.size() + 1) + .mapToObj(k -> k + " | " + strings.get(k - 1)) + .forEach(System.out::println); + System.out.println(); + } else if (i == 2) { + System.out.println("Введите текст заметки..."); + String s = sc.nextLine(); + strings.add(LocalDateTime.now() + " | " + s); + } else if (i == 3) { + System.out.println("Введите номер изменяемой заметки..."); + int k = Integer.parseInt(sc.nextLine()); + + if (k > 0 && k <= strings.size()) { + System.out.println("Введите текст заметки..."); + String s = sc.nextLine(); + strings.set(k - 1, LocalDateTime.now() + " | " + s); + } else { + System.out.println("Введен несуществующий номер заметки"); + } + } else if (i == 4) { + System.out.println("Введите номер удаляемой заметки..."); + int k = Integer.parseInt(sc.nextLine()); + if (k > 0 && k <= strings.size()) { + strings.remove(k - 1); + } else { + System.out.println("Введен несуществующий номер заметки"); + } + } else if (i == 5) { + break; + } else { + System.out.println("Введен неверный номер опции"); + } + } catch (NumberFormatException e) { + System.out.println("Ошибка при вводе числа"); + } + } + } +} diff --git a/2023-01/spring-03-arch/solution02_codeface/.gitignore b/2023-01/spring-03-arch/solution02_codeface/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution02_codeface/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution02_codeface/pom.xml b/2023-01/spring-03-arch/solution02_codeface/pom.xml new file mode 100644 index 00000000..602c054f --- /dev/null +++ b/2023-01/spring-03-arch/solution02_codeface/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution02_codeface + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution02_codeface/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution02_codeface/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..ea54bae3 --- /dev/null +++ b/2023-01/spring-03-arch/solution02_codeface/src/main/java/ru/otus/Main.java @@ -0,0 +1,79 @@ +package ru.otus; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.stream.IntStream; + +// Имена переменных, константы, выпрямление кода +public class Main { + + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + public static void main(String[] args) { + var notes = new ArrayList(); + var userInput = new Scanner(System.in); + + while (true) { + System.out.println("Выберите одно из следующих действий..."); + System.out.println("1. Вывести все заметки"); + System.out.println("2. Добавить заметку"); + System.out.println("3. Изменить заметку"); + System.out.println("4. Удалить заметку"); + System.out.println("5. Выйти"); + + try { + var selectedOptionNumber = Integer.parseInt(userInput.nextLine()); + + if (selectedOptionNumber == MENU_OPTION_SHOW_ALL_NOTES) { + System.out.println("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> k + " | " + notes.get(k - 1)) + .forEach(System.out::println); + System.out.println(); + } else if (selectedOptionNumber == MENU_OPTION_ADD_NEW_NOTE) { + System.out.println("Введите текст заметки..."); + var noteText = userInput.nextLine(); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.add(finalNoteText); + } else if (selectedOptionNumber == MENU_OPTION_UPDATE_NOTE) { + System.out.println("Введите номер изменяемой заметки..."); + + var updatedNoteNumber = Integer.parseInt(userInput.nextLine()); + + if (updatedNoteNumber <= 0 || updatedNoteNumber > notes.size()) { + System.out.println("Введен несуществующий номер заметки"); + continue; + } + + System.out.println("Введите текст заметки..."); + var noteText = userInput.nextLine(); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.set(updatedNoteNumber - 1, finalNoteText); + } else if (selectedOptionNumber == MENU_OPTION_DELETE_NOTE) { + System.out.println("Введите номер удаляемой заметки..."); + + var deletedNoteNumber = Integer.parseInt(userInput.nextLine()); + if (deletedNoteNumber <= 0 || deletedNoteNumber > notes.size()) { + System.out.println("Введен несуществующий номер заметки"); + continue; + } + + notes.remove(deletedNoteNumber - 1); + } else if (selectedOptionNumber == MENU_OPTION_EXIT) { + break; + } else { + System.out.println("Введен неверный номер опции"); + } + } catch (NumberFormatException e) { + System.out.println("Ошибка при вводе числа"); + } + + } + } +} diff --git a/2023-01/spring-03-arch/solution03_kiss/.gitignore b/2023-01/spring-03-arch/solution03_kiss/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution03_kiss/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution03_kiss/pom.xml b/2023-01/spring-03-arch/solution03_kiss/pom.xml new file mode 100644 index 00000000..cbe48958 --- /dev/null +++ b/2023-01/spring-03-arch/solution03_kiss/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution03_kiss + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution03_kiss/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution03_kiss/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..92d53d53 --- /dev/null +++ b/2023-01/spring-03-arch/solution03_kiss/src/main/java/ru/otus/Main.java @@ -0,0 +1,104 @@ +package ru.otus; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.stream.IntStream; + +// Вынос печати меню, чтения пункта меню и выполнения команд в методы. +// - Убрали один уровень вложенности +// - Отделили что делает приложение от того, как оно это делает +public class Main { + + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + public static void main(String[] args) { + var notes = new ArrayList(); + var userInput = new Scanner(System.in); + + while (true) { + outputMenu(); + try { + var selectedMenuItem = readSelectedOptionNumberFrom(userInput); + + if (selectedMenuItem == MENU_OPTION_SHOW_ALL_NOTES) { + showAllNotes(notes); + } else if (selectedMenuItem == MENU_OPTION_ADD_NEW_NOTE) { + addNewNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_UPDATE_NOTE) { + updateNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_DELETE_NOTE) { + deleteNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_EXIT){ + break; + } else { + System.out.println("Введен неверный номер опции"); + } + } catch (NumberFormatException e) { + System.out.println("Ошибка при вводе числа"); + } + + } + } + + private static void outputMenu(){ + System.out.println("Выберите одно из следующих действий..."); + System.out.println("1. Вывести все заметки"); + System.out.println("2. Добавить заметку"); + System.out.println("3. Изменить заметку"); + System.out.println("4. Удалить заметку"); + System.out.println("5. Выйти"); + } + + private static int readSelectedOptionNumberFrom(Scanner userInput) { + return Integer.parseInt(userInput.nextLine()); + } + + private static void showAllNotes(List notes) { + System.out.println("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> k + " | " + notes.get(k - 1)) + .forEach(System.out::println); + System.out.println(); + } + + private static void addNewNote(Scanner userInput, List notes) { + System.out.println("Введите текст заметки..."); + var noteText = userInput.nextLine(); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.add(finalNoteText); + } + + private static void updateNote(Scanner userInput, List notes) { + System.out.println("Введите номер изменяемой заметки..."); + + var updatedNoteNumber = Integer.parseInt(userInput.nextLine()); + if (updatedNoteNumber <= 0 || updatedNoteNumber > notes.size()) { + System.out.println("Введен несуществующий номер заметки"); + return; + } + + System.out.println("Введите текст заметки..."); + var noteText = userInput.nextLine(); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.set(updatedNoteNumber - 1, finalNoteText); + } + + private static void deleteNote(Scanner userInput, List notes) { + System.out.println("Введите номер удаляемой заметки..."); + + var deletedNoteNumber = Integer.parseInt(userInput.nextLine()); + if (deletedNoteNumber <= 0 || deletedNoteNumber > notes.size()) { + System.out.println("Введен несуществующий номер заметки"); + return; + } + + notes.remove(deletedNoteNumber - 1); + } + +} diff --git a/2023-01/spring-03-arch/solution04_kiss/.gitignore b/2023-01/spring-03-arch/solution04_kiss/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution04_kiss/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution04_kiss/pom.xml b/2023-01/spring-03-arch/solution04_kiss/pom.xml new file mode 100644 index 00000000..00837286 --- /dev/null +++ b/2023-01/spring-03-arch/solution04_kiss/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution04_kiss + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution04_kiss/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution04_kiss/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..35b05fac --- /dev/null +++ b/2023-01/spring-03-arch/solution04_kiss/src/main/java/ru/otus/Main.java @@ -0,0 +1,107 @@ +package ru.otus; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.IntStream; + +// Уменьшение вложенности в main за счет выноса обработки команд в метод + executionFlag +public class Main { + + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + public static void main(String[] args) { + var notes = new ArrayList(); + var userInput = new Scanner(System.in); + + var executionFlag = new AtomicBoolean(true); + while (executionFlag.get()) { + outputMenu(); + try { + var selectedMenuItem = readSelectedOptionNumberFrom(userInput); + processMenuCommand(selectedMenuItem, executionFlag, userInput, notes); + } catch (NumberFormatException e) { + System.out.println("Ошибка при вводе числа"); + } + } + } + + private static void outputMenu(){ + System.out.println("Выберите одно из следующих действий..."); + System.out.println("1. Вывести все заметки"); + System.out.println("2. Добавить заметку"); + System.out.println("3. Изменить заметку"); + System.out.println("4. Удалить заметку"); + System.out.println("5. Выйти"); + } + + private static void processMenuCommand(int selectedMenuItem, AtomicBoolean executionFlag, + Scanner userInput, List notes) { + if (selectedMenuItem == MENU_OPTION_SHOW_ALL_NOTES) { + showAllNotes(notes); + } else if (selectedMenuItem == MENU_OPTION_ADD_NEW_NOTE) { + addNewNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_UPDATE_NOTE) { + updateNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_DELETE_NOTE) { + deleteNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_EXIT){ + executionFlag.set(false); + } else { + System.out.println("Введен неверный номер опции"); + } + } + + private static int readSelectedOptionNumberFrom(Scanner userInput) { + return Integer.parseInt(userInput.nextLine()); + } + + private static void showAllNotes(List notes) { + System.out.println("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> k + " | " + notes.get(k - 1)) + .forEach(System.out::println); + System.out.println(); + } + + private static void addNewNote(Scanner userInput, List notes) { + System.out.println("Введите текст заметки..."); + var noteText = userInput.nextLine(); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.add(finalNoteText); + } + + private static void updateNote(Scanner userInput, List notes) { + System.out.println("Введите номер изменяемой заметки..."); + + var updatedNoteNumber = Integer.parseInt(userInput.nextLine()); + if (updatedNoteNumber <= 0 || updatedNoteNumber > notes.size()) { + System.out.println("Введен несуществующий номер заметки"); + return; + } + + System.out.println("Введите текст заметки..."); + var noteText = userInput.nextLine(); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.set(updatedNoteNumber - 1, finalNoteText); + } + + private static void deleteNote(Scanner userInput, List notes) { + System.out.println("Введите номер удаляемой заметки..."); + + var deletedNoteNumber = Integer.parseInt(userInput.nextLine()); + if (deletedNoteNumber <= 0 || deletedNoteNumber > notes.size()) { + System.out.println("Введен несуществующий номер заметки"); + return; + } + + notes.remove(deletedNoteNumber - 1); + } + +} diff --git a/2023-01/spring-03-arch/solution05_dry/.gitignore b/2023-01/spring-03-arch/solution05_dry/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution05_dry/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution05_dry/pom.xml b/2023-01/spring-03-arch/solution05_dry/pom.xml new file mode 100644 index 00000000..f30426fa --- /dev/null +++ b/2023-01/spring-03-arch/solution05_dry/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution05_dry + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution05_dry/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution05_dry/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..bf81db2c --- /dev/null +++ b/2023-01/spring-03-arch/solution05_dry/src/main/java/ru/otus/Main.java @@ -0,0 +1,118 @@ +package ru.otus; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.IntStream; + +// Вынос логики ввода-вывода +public class Main { + + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + public static void main(String[] args) { + var notes = new ArrayList(); + var userInput = new Scanner(System.in); + + var executionFlag = new AtomicBoolean(true); + while (executionFlag.get()) { + outputMenu(); + try { + var selectedMenuItem = readSelectedOptionNumberFrom(userInput); + processMenuCommand(selectedMenuItem, executionFlag, userInput, notes); + } catch (NumberFormatException e) { + outputString("Ошибка при вводе числа"); + } + } + } + + private static void outputMenu(){ + outputString("Выберите одно из следующих действий..."); + outputString("1. Вывести все заметки"); + outputString("2. Добавить заметку"); + outputString("3. Изменить заметку"); + outputString("4. Удалить заметку"); + outputString("5. Выйти"); + } + + private static void processMenuCommand(int selectedMenuItem, AtomicBoolean executionFlag, + Scanner userInput, List notes) { + if (selectedMenuItem == MENU_OPTION_SHOW_ALL_NOTES) { + showAllNotes(notes); + } else if (selectedMenuItem == MENU_OPTION_ADD_NEW_NOTE) { + addNewNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_UPDATE_NOTE) { + updateNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_DELETE_NOTE) { + deleteNote(userInput, notes); + } else if (selectedMenuItem == MENU_OPTION_EXIT){ + executionFlag.set(false); + } else { + outputString("Введен неверный номер опции"); + } + } + + private static int readSelectedOptionNumberFrom(Scanner userInput) { + return readInt(userInput); + } + + private static void showAllNotes(List notes) { + outputString("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> k + " | " + notes.get(k - 1)) + .forEach(Main::outputString); + outputString(""); + } + + private static void addNewNote(Scanner userInput, List notes) { + var noteText = readStringWithPrompt(userInput, "Введите текст заметки..."); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.add(finalNoteText); + } + + private static void updateNote(Scanner userInput, List notes) { + int updatedNoteNumber = readIntWithPrompt(userInput, "Введите номер изменяемой заметки..."); + if (updatedNoteNumber <= 0 || updatedNoteNumber > notes.size()) { + outputString("Введен несуществующий номер заметки"); + return; + } + var noteText = readStringWithPrompt(userInput, "Введите текст заметки..."); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.set(updatedNoteNumber - 1, finalNoteText); + } + + private static void deleteNote(Scanner userInput, List notes) { + var deletedNoteNumber = readIntWithPrompt(userInput, "Введите номер удаляемой заметки..."); + if (deletedNoteNumber <= 0 || deletedNoteNumber > notes.size()) { + outputString("Введен несуществующий номер заметки"); + return; + } + + notes.remove(deletedNoteNumber - 1); + } + + private static void outputString(String s){ + System.out.println(s); + } + + private static int readInt(Scanner userInput){ + return Integer.parseInt(userInput.nextLine()); + } + + private static int readIntWithPrompt(Scanner userInput, String prompt){ + outputString(prompt); + return Integer.parseInt(userInput.nextLine()); + } + + private static String readStringWithPrompt(Scanner userInput, String prompt){ + outputString(prompt); + return userInput.nextLine(); + } + +} diff --git a/2023-01/spring-03-arch/solution06_dry/.gitignore b/2023-01/spring-03-arch/solution06_dry/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution06_dry/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution06_dry/pom.xml b/2023-01/spring-03-arch/solution06_dry/pom.xml new file mode 100644 index 00000000..35286559 --- /dev/null +++ b/2023-01/spring-03-arch/solution06_dry/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution06_dry + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..d652ca12 --- /dev/null +++ b/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/Main.java @@ -0,0 +1,127 @@ +package ru.otus; + +import ru.otus.exceptions.MenuItemIndexOutOfBoundsException; +import ru.otus.exceptions.NoteIndexOutOfBoundsException; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.IntStream; + +// Вынос проверки существования выбранной команды в метод checkNoteNumber, +// централизованная обработка ошибок +public class Main { + + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + public static void main(String[] args) { + var notes = new ArrayList(); + var userInput = new Scanner(System.in); + + var executionFlag = new AtomicBoolean(true); + while (executionFlag.get()) { + outputMenu(); + try { + var selectedMenuItem = readSelectedOptionNumberFrom(userInput); + processMenuCommand(selectedMenuItem, executionFlag, userInput, notes); + + } catch (NumberFormatException e) { + outputString("Ошибка при вводе числа"); + } catch (MenuItemIndexOutOfBoundsException e) { + outputString("Введен неверный номер опции"); + } catch (NoteIndexOutOfBoundsException e) { + outputString("Введен несуществующий номер заметки"); + } + } + } + + private static void outputMenu(){ + outputString("Выберите одно из следующих действий..."); + outputString("1. Вывести все заметки"); + outputString("2. Добавить заметку"); + outputString("3. Изменить заметку"); + outputString("4. Удалить заметку"); + outputString("5. Выйти"); + } + + private static void processMenuCommand(int selectedMenuItemIndex, AtomicBoolean executionFlag, + Scanner userInput, List notes) { + if (selectedMenuItemIndex == MENU_OPTION_SHOW_ALL_NOTES) { + showAllNotes(notes); + } else if (selectedMenuItemIndex == MENU_OPTION_ADD_NEW_NOTE) { + addNewNote(userInput, notes); + } else if (selectedMenuItemIndex == MENU_OPTION_UPDATE_NOTE) { + updateNote(userInput, notes); + } else if (selectedMenuItemIndex == MENU_OPTION_DELETE_NOTE) { + deleteNote(userInput, notes); + } else if (selectedMenuItemIndex == MENU_OPTION_EXIT){ + executionFlag.set(false); + } else { + throw new MenuItemIndexOutOfBoundsException("Given menu item index is out of range"); + } + } + + private static int readSelectedOptionNumberFrom(Scanner userInput) { + return readInt(userInput); + } + + private static void showAllNotes(List notes) { + outputString("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> k + " | " + notes.get(k - 1)) + .forEach(Main::outputString); + outputString(""); + } + + private static void addNewNote(Scanner userInput, List notes) { + var noteText = readStringWithPrompt(userInput, "Введите текст заметки..."); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.add(finalNoteText); + } + + private static void checkNoteNumber(int noteNumber, List notes) { + if (noteNumber <= 0 || noteNumber > notes.size()) { + throw new NoteIndexOutOfBoundsException("Given number of note is out of range"); + } + } + + private static void updateNote(Scanner userInput, List notes) { + var updatedNoteNumber = readIntWithPrompt(userInput, "Введите номер изменяемой заметки..."); + checkNoteNumber(updatedNoteNumber, notes); + + var noteText = readStringWithPrompt(userInput, "Введите текст заметки..."); + var finalNoteText = LocalDateTime.now() + " | " + noteText; + notes.set(updatedNoteNumber - 1, finalNoteText); + } + + private static void deleteNote(Scanner userInput, List notes) { + var deletedNoteNumber = readIntWithPrompt(userInput, "Введите номер удаляемой заметки..."); + checkNoteNumber(deletedNoteNumber, notes); + + notes.remove(deletedNoteNumber - 1); + } + + private static void outputString(String s){ + System.out.println(s); + } + + private static int readInt(Scanner userInput){ + return Integer.parseInt(userInput.nextLine()); + } + + private static int readIntWithPrompt(Scanner userInput, String prompt){ + outputString(prompt); + return Integer.parseInt(userInput.nextLine()); + } + + private static String readStringWithPrompt(Scanner userInput, String prompt){ + outputString(prompt); + return userInput.nextLine(); + } +} diff --git a/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java new file mode 100644 index 00000000..5fa79742 --- /dev/null +++ b/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class MenuItemIndexOutOfBoundsException extends IndexOutOfBoundsException { + public MenuItemIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java new file mode 100644 index 00000000..2c9592f6 --- /dev/null +++ b/2023-01/spring-03-arch/solution06_dry/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class NoteIndexOutOfBoundsException extends IndexOutOfBoundsException { + public NoteIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution07_srp/.gitignore b/2023-01/spring-03-arch/solution07_srp/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution07_srp/pom.xml b/2023-01/spring-03-arch/solution07_srp/pom.xml new file mode 100644 index 00000000..c1afb624 --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution07_srp + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..99416733 --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/Main.java @@ -0,0 +1,109 @@ +package ru.otus; + +import ru.otus.exceptions.NoteIndexOutOfBoundsException; +import ru.otus.exceptions.MenuItemIndexOutOfBoundsException; +import ru.otus.model.Note; +import ru.otus.services.ConsoleIOService; +import ru.otus.services.NoteConverter; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.IntStream; + +// Note, ConsoleIOService, NoteConverter +public class Main { + + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + public static void main(String[] args) { + var notes = new ArrayList(); + var ioService = new ConsoleIOService(); + + var executionFlag = new AtomicBoolean(true); + while (executionFlag.get()) { + outputMenu(ioService); + try { + var selectedMenuItem = readSelectedOptionNumberFrom(ioService); + processMenuCommand(selectedMenuItem, executionFlag, ioService, notes); + + } catch (NumberFormatException e) { + ioService.outputString("Ошибка при вводе числа"); + } catch (MenuItemIndexOutOfBoundsException e) { + ioService.outputString("Введен неверный номер опции"); + } catch (NoteIndexOutOfBoundsException e) { + ioService.outputString("Введен несуществующий номер заметки"); + } + } + } + + private static void outputMenu(ConsoleIOService ioService){ + ioService.outputString("Выберите одно из следующих действий..."); + ioService.outputString("1. Вывести все заметки"); + ioService.outputString("2. Добавить заметку"); + ioService.outputString("3. Изменить заметку"); + ioService.outputString("4. Удалить заметку"); + ioService.outputString("5. Выйти"); + } + + private static void processMenuCommand(int selectedMenuItemIndex, AtomicBoolean executionFlag, + ConsoleIOService ioService, List notes) { + if (selectedMenuItemIndex == MENU_OPTION_SHOW_ALL_NOTES) { + showAllNotes(ioService, notes); + } else if (selectedMenuItemIndex == MENU_OPTION_ADD_NEW_NOTE) { + addNewNote(ioService, notes); + } else if (selectedMenuItemIndex == MENU_OPTION_UPDATE_NOTE) { + updateNote(ioService, notes); + } else if (selectedMenuItemIndex == MENU_OPTION_DELETE_NOTE) { + deleteNote(ioService, notes); + } else if (selectedMenuItemIndex == MENU_OPTION_EXIT){ + executionFlag.set(false); + } else { + throw new MenuItemIndexOutOfBoundsException("Given menu item index is out of range"); + } + } + + private static int readSelectedOptionNumberFrom(ConsoleIOService ioService) { + return ioService.readInt(); + } + + private static void showAllNotes(ConsoleIOService ioService, List notes) { + var noteConverter = new NoteConverter(); + ioService.outputString("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> noteConverter.convertNoteToString(k, notes.get(k - 1))) + .forEach(ioService::outputString); + ioService.outputString(""); + } + + private static void addNewNote(ConsoleIOService ioService, List notes) { + var noteText = ioService.readStringWithPrompt("Введите текст заметки..."); + notes.add( Note.of(noteText)); + } + + private static void checkNoteNumber(int noteNumber, List notes) { + if (noteNumber <= 0 || noteNumber > notes.size()) { + throw new NoteIndexOutOfBoundsException("Given number of note is out of range"); + } + } + + private static void updateNote(ConsoleIOService ioService, List notes) { + var updatedNoteNumber = ioService.readIntWithPrompt("Введите номер изменяемой заметки..."); + checkNoteNumber(updatedNoteNumber, notes); + + var noteText = ioService.readStringWithPrompt("Введите текст заметки..."); + notes.set(updatedNoteNumber - 1, Note.of(noteText)); + } + + private static void deleteNote(ConsoleIOService ioService, List notes) { + var deletedNoteNumber = ioService.readIntWithPrompt("Введите номер удаляемой заметки..."); + checkNoteNumber(deletedNoteNumber, notes); + + notes.remove(deletedNoteNumber - 1); + } + +} diff --git a/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java new file mode 100644 index 00000000..5fa79742 --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class MenuItemIndexOutOfBoundsException extends IndexOutOfBoundsException { + public MenuItemIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java new file mode 100644 index 00000000..2c9592f6 --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class NoteIndexOutOfBoundsException extends IndexOutOfBoundsException { + public NoteIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/model/Note.java b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/model/Note.java new file mode 100644 index 00000000..e8dea623 --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/model/Note.java @@ -0,0 +1,26 @@ +package ru.otus.model; + +import java.time.LocalDateTime; + +public class Note { + private final LocalDateTime creationTime; + private final String text; + + public Note(String text) { + this.creationTime = LocalDateTime.now(); + this.text = text; + } + + public static Note of(String text) { + return new Note(text); + } + + public LocalDateTime getCreationTime() { + return creationTime; + } + + public String getText() { + return text; + } + +} diff --git a/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/ConsoleIOService.java b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/ConsoleIOService.java new file mode 100644 index 00000000..bf773074 --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/ConsoleIOService.java @@ -0,0 +1,29 @@ +package ru.otus.services; + +import java.util.Scanner; + +public class ConsoleIOService { + private final Scanner userInput; + + public ConsoleIOService() { + userInput = new Scanner(System.in); + } + + public void outputString(String s){ + System.out.println(s); + } + + public int readInt(){ + return Integer.parseInt(userInput.nextLine()); + } + + public int readIntWithPrompt(String prompt){ + outputString(prompt); + return Integer.parseInt(userInput.nextLine()); + } + + public String readStringWithPrompt(String prompt){ + outputString(prompt); + return userInput.nextLine(); + } +} diff --git a/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/NoteConverter.java b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/NoteConverter.java new file mode 100644 index 00000000..d8f8445b --- /dev/null +++ b/2023-01/spring-03-arch/solution07_srp/src/main/java/ru/otus/services/NoteConverter.java @@ -0,0 +1,9 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +public class NoteConverter { + public String convertNoteToString(int noteNumber, Note note) { + return noteNumber + " | " + note.getCreationTime() + " | " + note.getText(); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/.gitignore b/2023-01/spring-03-arch/solution08_srp/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution08_srp/pom.xml b/2023-01/spring-03-arch/solution08_srp/pom.xml new file mode 100644 index 00000000..e5af6269 --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution08_srp + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..1dd7742a --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/Main.java @@ -0,0 +1,10 @@ +package ru.otus; + +import ru.otus.services.ApplicationRunner; + +// ApplicationRunner, MenuCommandsProcessor, NotesService +public class Main { + public static void main(String[] args) { + new ApplicationRunner().run(); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java new file mode 100644 index 00000000..5fa79742 --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class MenuItemIndexOutOfBoundsException extends IndexOutOfBoundsException { + public MenuItemIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java new file mode 100644 index 00000000..2c9592f6 --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class NoteIndexOutOfBoundsException extends IndexOutOfBoundsException { + public NoteIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/model/Note.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/model/Note.java new file mode 100644 index 00000000..10d3b8ee --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/model/Note.java @@ -0,0 +1,53 @@ +package ru.otus.model; + +import java.time.LocalDateTime; +import java.util.UUID; + +public class Note { + private final String id; + private final LocalDateTime creationTime; + private final String text; + + public Note(String text) { + this.id = UUID.randomUUID().toString(); + this.creationTime = LocalDateTime.now(); + this.text = text; + } + + public Note(String id, String text) { + this.id = id; + this.creationTime = LocalDateTime.now(); + this.text = text; + } + + public Note(String id, LocalDateTime creationTime, String text) { + this.id = id; + this.creationTime = creationTime; + this.text = text; + } + + public static Note of(String text) { + return new Note(text); + } + + public static Note of(String id, String text) { + return new Note(id, text); + } + + public String getId() { + return id; + } + + public LocalDateTime getCreationTime() { + return creationTime; + } + + public String getText() { + return text; + } + + + public Note copy() { + return new Note(id, creationTime, text); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ApplicationRunner.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ApplicationRunner.java new file mode 100644 index 00000000..21aa98b1 --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ApplicationRunner.java @@ -0,0 +1,72 @@ +package ru.otus.services; + +import ru.otus.exceptions.MenuItemIndexOutOfBoundsException; +import ru.otus.exceptions.NoteIndexOutOfBoundsException; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class ApplicationRunner { + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + private final ConsoleIOService ioService; + private final AtomicBoolean executionFlag; + private final MenuCommandsProcessor commandsProcessor; + + + public ApplicationRunner() { + ioService = new ConsoleIOService(); + executionFlag = new AtomicBoolean(true); + commandsProcessor = new MenuCommandsProcessor(); + + } + + public void run() { + while (executionFlag.get()) { + outputMenu(); + try { + var selectedMenuItem = readSelectedOptionNumber(); + processMenuCommand(selectedMenuItem); + + } catch (NumberFormatException e) { + ioService.outputString("Ошибка при вводе числа"); + } catch (MenuItemIndexOutOfBoundsException e) { + ioService.outputString("Введен неверный номер опции"); + } catch (NoteIndexOutOfBoundsException e) { + ioService.outputString("Введен несуществующий номер заметки"); + } + } + } + + private void outputMenu(){ + ioService.outputString("Выберите одно из следующих действий..."); + ioService.outputString("1. Вывести все заметки"); + ioService.outputString("2. Добавить заметку"); + ioService.outputString("3. Изменить заметку"); + ioService.outputString("4. Удалить заметку"); + ioService.outputString("5. Выйти"); + } + + private void processMenuCommand(int selectedMenuItemIndex) { + if (selectedMenuItemIndex == MENU_OPTION_SHOW_ALL_NOTES) { + commandsProcessor.showAllNotes(ioService); + } else if (selectedMenuItemIndex == MENU_OPTION_ADD_NEW_NOTE) { + commandsProcessor.addNewNote(ioService); + } else if (selectedMenuItemIndex == MENU_OPTION_UPDATE_NOTE) { + commandsProcessor.updateNote(ioService); + } else if (selectedMenuItemIndex == MENU_OPTION_DELETE_NOTE) { + commandsProcessor.deleteNote(ioService); + } else if (selectedMenuItemIndex == MENU_OPTION_EXIT){ + executionFlag.set(false); + } else { + throw new MenuItemIndexOutOfBoundsException("Given menu item index is out of range"); + } + } + + private int readSelectedOptionNumber() { + return ioService.readInt(); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ConsoleIOService.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ConsoleIOService.java new file mode 100644 index 00000000..bf773074 --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/ConsoleIOService.java @@ -0,0 +1,29 @@ +package ru.otus.services; + +import java.util.Scanner; + +public class ConsoleIOService { + private final Scanner userInput; + + public ConsoleIOService() { + userInput = new Scanner(System.in); + } + + public void outputString(String s){ + System.out.println(s); + } + + public int readInt(){ + return Integer.parseInt(userInput.nextLine()); + } + + public int readIntWithPrompt(String prompt){ + outputString(prompt); + return Integer.parseInt(userInput.nextLine()); + } + + public String readStringWithPrompt(String prompt){ + outputString(prompt); + return userInput.nextLine(); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/MenuCommandsProcessor.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/MenuCommandsProcessor.java new file mode 100644 index 00000000..b9541d8b --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/MenuCommandsProcessor.java @@ -0,0 +1,58 @@ +package ru.otus.services; + +import ru.otus.model.Note; +import ru.otus.exceptions.NoteIndexOutOfBoundsException; + +import java.util.stream.IntStream; + +public class MenuCommandsProcessor { + private final NotesService notesService; + + public MenuCommandsProcessor() { + notesService = new NotesService(); + } + + public void showAllNotes(ConsoleIOService ioService) { + var noteConverter = new NoteConverter(); + var notes = notesService.getAll(); + ioService.outputString("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> noteConverter.convertNoteToString(k, notes.get(k - 1))) + .forEach(ioService::outputString); + ioService.outputString(""); + } + + public void addNewNote(ConsoleIOService ioService) { + var noteText = ioService.readStringWithPrompt("Введите текст заметки..."); + notesService.save(Note.of(noteText)); + } + + public void updateNote(ConsoleIOService ioService) { + var notes = notesService.getAll(); + + var updatedNoteNumber = ioService.readIntWithPrompt("Введите номер изменяемой заметки..."); + checkNoteNumber(updatedNoteNumber, notes.size()); + + var noteText = ioService.readStringWithPrompt("Введите текст заметки..."); + + var updatedNote = notes.get(updatedNoteNumber - 1); + notesService.save(Note.of(updatedNote.getId(), noteText)); + } + + public void deleteNote(ConsoleIOService ioService) { + var notes = notesService.getAll(); + + var deletedNoteNumber = ioService.readIntWithPrompt("Введите номер удаляемой заметки..."); + checkNoteNumber(deletedNoteNumber, notes.size()); + + var updatedNote = notes.get(deletedNoteNumber - 1); + notesService.remove(updatedNote.getId()); + } + + private static void checkNoteNumber(int noteNumber, int notesCount) { + if (noteNumber <= 0 || noteNumber > notesCount) { + throw new NoteIndexOutOfBoundsException("Given number of note is out of range"); + } + } + +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NoteConverter.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NoteConverter.java new file mode 100644 index 00000000..d8f8445b --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NoteConverter.java @@ -0,0 +1,9 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +public class NoteConverter { + public String convertNoteToString(int noteNumber, Note note) { + return noteNumber + " | " + note.getCreationTime() + " | " + note.getText(); + } +} diff --git a/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NotesService.java b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NotesService.java new file mode 100644 index 00000000..8d899f25 --- /dev/null +++ b/2023-01/spring-03-arch/solution08_srp/src/main/java/ru/otus/services/NotesService.java @@ -0,0 +1,26 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +import java.util.*; +import java.util.stream.Collectors; + +public class NotesService { + private final Map notes; + + public NotesService() { + notes = new HashMap<>(); + } + + public List getAll() { + return notes.values().stream().map(Note::copy).collect(Collectors.toList()); + } + + public void save(Note note) { + notes.put(note.getId(), note); + } + + public void remove(String id) { + notes.remove(id); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/.gitignore b/2023-01/spring-03-arch/solution09_dip/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution09_dip/pom.xml b/2023-01/spring-03-arch/solution09_dip/pom.xml new file mode 100644 index 00000000..3906f899 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + ru.otus + solution09_dip + 1.0 + + + + 17 + 17 + UTF-8 + + + + + diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..a27f1448 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/Main.java @@ -0,0 +1,20 @@ +package ru.otus; + +import ru.otus.config.AppSettings; +import ru.otus.services.*; + +// +AppSettings, +ApplicationStopService, IOService стал Streams, методы MenuCommandsProcessor очистились от IOService +public class Main { + public static void main(String[] args) { + var appSettings = new AppSettings(true, "dd.mm.YYYY HH:mm:ss"); + var ioService = new IOServiceStreams(System.out, System.in); + var applicationStopService = new ApplicationStopServiceImpl(ioService, appSettings); + var notesService = new NotesServiceImpl(); + var noteConverter = new NoteConverterImpl(appSettings); + var menuCommandsProcessor = new MenuCommandsProcessorImpl(ioService, notesService, + noteConverter, applicationStopService); + + new ApplicationRunner(ioService, applicationStopService, menuCommandsProcessor) + .run(); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/config/AppSettings.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/config/AppSettings.java new file mode 100644 index 00000000..b2344ece --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/config/AppSettings.java @@ -0,0 +1,19 @@ +package ru.otus.config; + +public class AppSettings { + private final boolean confirmExit; + private final String dateTimeFormat; + + public AppSettings(boolean confirmExit, String dateTimeFormat) { + this.confirmExit = confirmExit; + this.dateTimeFormat = dateTimeFormat; + } + + public boolean isConfirmExit() { + return confirmExit; + } + + public String getDateTimeFormat() { + return dateTimeFormat; + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java new file mode 100644 index 00000000..5fa79742 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class MenuItemIndexOutOfBoundsException extends IndexOutOfBoundsException { + public MenuItemIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java new file mode 100644 index 00000000..2c9592f6 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class NoteIndexOutOfBoundsException extends IndexOutOfBoundsException { + public NoteIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/model/Note.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/model/Note.java new file mode 100644 index 00000000..10d3b8ee --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/model/Note.java @@ -0,0 +1,53 @@ +package ru.otus.model; + +import java.time.LocalDateTime; +import java.util.UUID; + +public class Note { + private final String id; + private final LocalDateTime creationTime; + private final String text; + + public Note(String text) { + this.id = UUID.randomUUID().toString(); + this.creationTime = LocalDateTime.now(); + this.text = text; + } + + public Note(String id, String text) { + this.id = id; + this.creationTime = LocalDateTime.now(); + this.text = text; + } + + public Note(String id, LocalDateTime creationTime, String text) { + this.id = id; + this.creationTime = creationTime; + this.text = text; + } + + public static Note of(String text) { + return new Note(text); + } + + public static Note of(String id, String text) { + return new Note(id, text); + } + + public String getId() { + return id; + } + + public LocalDateTime getCreationTime() { + return creationTime; + } + + public String getText() { + return text; + } + + + public Note copy() { + return new Note(id, creationTime, text); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationRunner.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationRunner.java new file mode 100644 index 00000000..e10ac8c9 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationRunner.java @@ -0,0 +1,71 @@ +package ru.otus.services; + +import ru.otus.exceptions.MenuItemIndexOutOfBoundsException; +import ru.otus.exceptions.NoteIndexOutOfBoundsException; + +public class ApplicationRunner { + private static final int MENU_OPTION_SHOW_ALL_NOTES = 1; + private static final int MENU_OPTION_ADD_NEW_NOTE = 2; + private static final int MENU_OPTION_UPDATE_NOTE = 3; + private static final int MENU_OPTION_DELETE_NOTE = 4; + private static final int MENU_OPTION_EXIT = 5; + + private final IOService ioService; + private final ApplicationStopService applicationStopService; + private final MenuCommandsProcessor commandsProcessor; + + + public ApplicationRunner(IOService ioService, + ApplicationStopService applicationStopService, + MenuCommandsProcessor commandsProcessor) { + this.ioService = ioService; + this.applicationStopService = applicationStopService; + this.commandsProcessor = commandsProcessor; + } + + public void run() { + while (applicationStopService.isApplicationRunning()) { + outputMenu(); + try { + var selectedMenuItem = readSelectedOptionNumber(); + processMenuCommand(selectedMenuItem); + + } catch (NumberFormatException e) { + ioService.outputString("Ошибка при вводе числа"); + } catch (MenuItemIndexOutOfBoundsException e) { + ioService.outputString("Введен неверный номер опции"); + } catch (NoteIndexOutOfBoundsException e) { + ioService.outputString("Введен несуществующий номер заметки"); + } + } + } + + private void outputMenu(){ + ioService.outputString("Выберите одно из следующих действий..."); + ioService.outputString("1. Вывести все заметки"); + ioService.outputString("2. Добавить заметку"); + ioService.outputString("3. Изменить заметку"); + ioService.outputString("4. Удалить заметку"); + ioService.outputString("5. Выйти"); + } + + private void processMenuCommand(int selectedMenuItemIndex) { + if (selectedMenuItemIndex == MENU_OPTION_SHOW_ALL_NOTES) { + commandsProcessor.showAllNotes(); + } else if (selectedMenuItemIndex == MENU_OPTION_ADD_NEW_NOTE) { + commandsProcessor.addNewNote(); + } else if (selectedMenuItemIndex == MENU_OPTION_UPDATE_NOTE) { + commandsProcessor.updateNote(); + } else if (selectedMenuItemIndex == MENU_OPTION_DELETE_NOTE) { + commandsProcessor.deleteNote(); + } else if (selectedMenuItemIndex == MENU_OPTION_EXIT){ + commandsProcessor.stopApplication(); + } else { + throw new MenuItemIndexOutOfBoundsException("Given menu item index is out of range"); + } + } + + private int readSelectedOptionNumber() { + return ioService.readInt(); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopService.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopService.java new file mode 100644 index 00000000..31d612f9 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopService.java @@ -0,0 +1,6 @@ +package ru.otus.services; + +public interface ApplicationStopService { + boolean isApplicationRunning(); + void stopApplication(); +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java new file mode 100644 index 00000000..4a99b272 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java @@ -0,0 +1,34 @@ +package ru.otus.services; + +import ru.otus.config.AppSettings; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class ApplicationStopServiceImpl implements ApplicationStopService { + + private final IOService ioService; + private final AppSettings appSettings; + private final AtomicBoolean executionFlag; + + public ApplicationStopServiceImpl(IOService ioService, AppSettings appSettings) { + this.ioService = ioService; + this.appSettings = appSettings; + this.executionFlag = new AtomicBoolean(true); + } + + @Override + public boolean isApplicationRunning() { + return executionFlag.get(); + } + + @Override + public void stopApplication() { + if (appSettings.isConfirmExit()) { + var exitConfirmation = ioService.readStringWithPrompt("Действительно выйти? (да/нет)"); + if (exitConfirmation.equalsIgnoreCase("нет")) { + return; + } + } + executionFlag.set(false); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOService.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOService.java new file mode 100644 index 00000000..5247912b --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOService.java @@ -0,0 +1,11 @@ +package ru.otus.services; + +public interface IOService { + void outputString(String s); + + int readInt(); + + int readIntWithPrompt(String prompt); + + String readStringWithPrompt(String prompt); +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOServiceStreams.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOServiceStreams.java new file mode 100644 index 00000000..ca7dff21 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/IOServiceStreams.java @@ -0,0 +1,37 @@ +package ru.otus.services; + +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Scanner; + +public class IOServiceStreams implements IOService { + private final PrintStream output; + private final Scanner input; + + public IOServiceStreams(PrintStream outputStream, InputStream inputStream) { + output = outputStream; + input = new Scanner(inputStream); + } + + @Override + public void outputString(String s){ + output.println(s); + } + + @Override + public int readInt(){ + return Integer.parseInt(input.nextLine()); + } + + @Override + public int readIntWithPrompt(String prompt){ + outputString(prompt); + return Integer.parseInt(input.nextLine()); + } + + @Override + public String readStringWithPrompt(String prompt){ + outputString(prompt); + return input.nextLine(); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessor.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessor.java new file mode 100644 index 00000000..3ce09c81 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessor.java @@ -0,0 +1,13 @@ +package ru.otus.services; + +public interface MenuCommandsProcessor { + void showAllNotes(); + + void addNewNote(); + + void updateNote(); + + void deleteNote(); + + void stopApplication(); +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessorImpl.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessorImpl.java new file mode 100644 index 00000000..374e472e --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/MenuCommandsProcessorImpl.java @@ -0,0 +1,74 @@ +package ru.otus.services; + +import ru.otus.model.Note; +import ru.otus.exceptions.NoteIndexOutOfBoundsException; + +import java.util.stream.IntStream; + +public class MenuCommandsProcessorImpl implements MenuCommandsProcessor { + private final IOService ioService; + private final NotesService notesService; + private final NoteConverter noteConverter; + private final ApplicationStopService applicationStopService; + + public MenuCommandsProcessorImpl(IOService ioService, NotesService notesService, + NoteConverter noteConverter, + ApplicationStopService applicationStopService) { + this.ioService = ioService; + this.notesService = notesService; + this.noteConverter = noteConverter; + this.applicationStopService = applicationStopService; + } + + @Override + public void showAllNotes() { + var notes = notesService.getAll(); + ioService.outputString("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> noteConverter.convertNoteToString(k, notes.get(k - 1))) + .forEach(ioService::outputString); + ioService.outputString(""); + } + + @Override + public void addNewNote() { + var noteText = ioService.readStringWithPrompt("Введите текст заметки..."); + notesService.save(Note.of(noteText)); + } + + @Override + public void updateNote() { + var notes = notesService.getAll(); + + var updatedNoteNumber = ioService.readIntWithPrompt("Введите номер изменяемой заметки..."); + checkNoteNumber(updatedNoteNumber, notes.size()); + + var noteText = ioService.readStringWithPrompt("Введите текст заметки..."); + + var updatedNote = notes.get(updatedNoteNumber - 1); + notesService.save(Note.of(updatedNote.getId(), noteText)); + } + + @Override + public void deleteNote() { + var notes = notesService.getAll(); + + var deletedNoteNumber = ioService.readIntWithPrompt("Введите номер удаляемой заметки..."); + checkNoteNumber(deletedNoteNumber, notes.size()); + + var updatedNote = notes.get(deletedNoteNumber - 1); + notesService.remove(updatedNote.getId()); + } + + @Override + public void stopApplication() { + applicationStopService.stopApplication(); + } + + private static void checkNoteNumber(int noteNumber, int notesCount) { + if (noteNumber <= 0 || noteNumber > notesCount) { + throw new NoteIndexOutOfBoundsException("Given number of note is out of range"); + } + } + +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverter.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverter.java new file mode 100644 index 00000000..7dfe1e57 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverter.java @@ -0,0 +1,7 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +public interface NoteConverter { + String convertNoteToString(int noteNumber, Note note); +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverterImpl.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverterImpl.java new file mode 100644 index 00000000..1b351c82 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NoteConverterImpl.java @@ -0,0 +1,21 @@ +package ru.otus.services; + +import ru.otus.config.AppSettings; +import ru.otus.model.Note; + + +import java.time.format.DateTimeFormatter; + +public class NoteConverterImpl implements NoteConverter { + private final AppSettings appSettings; + + public NoteConverterImpl(AppSettings appSettings) { + this.appSettings = appSettings; + } + + @Override + public String convertNoteToString(int noteNumber, Note note) { + var dateTimeFormatter = DateTimeFormatter.ofPattern(appSettings.getDateTimeFormat()); + return noteNumber + " | " + dateTimeFormatter.format(note.getCreationTime()) + " | " + note.getText(); + } +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesService.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesService.java new file mode 100644 index 00000000..019c6cd7 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesService.java @@ -0,0 +1,13 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +import java.util.List; + +public interface NotesService { + List getAll(); + + void save(Note note); + + void remove(String id); +} diff --git a/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesServiceImpl.java b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesServiceImpl.java new file mode 100644 index 00000000..b8c15298 --- /dev/null +++ b/2023-01/spring-03-arch/solution09_dip/src/main/java/ru/otus/services/NotesServiceImpl.java @@ -0,0 +1,31 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class NotesServiceImpl implements NotesService { + private final Map notes; + + public NotesServiceImpl() { + notes = new HashMap<>(); + } + + @Override + public List getAll() { + return notes.values().stream().map(Note::copy).collect(Collectors.toList()); + } + + @Override + public void save(Note note) { + notes.put(note.getId(), note); + } + + @Override + public void remove(String id) { + notes.remove(id); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/.gitignore b/2023-01/spring-03-arch/solution10_ocp_isp/.gitignore new file mode 100644 index 00000000..e62c33c2 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/.gitignore @@ -0,0 +1,4 @@ +.idea/ +*.iml + +target/ diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/pom.xml b/2023-01/spring-03-arch/solution10_ocp_isp/pom.xml new file mode 100644 index 00000000..f1b6961c --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + ru.otus + solution10_ocp_isp + 1.0 + + + + 17 + 17 + UTF-8 + 5.9.2 + 4.9.0 + 3.23.1 + + + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-params + ${junit.jupiter.version} + test + + + + + org.mockito + mockito-core + ${mockito.version} + test + + + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/Main.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/Main.java new file mode 100644 index 00000000..46efea5d --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/Main.java @@ -0,0 +1,46 @@ +package ru.otus; + +import ru.otus.config.AppSettings; +import ru.otus.services.*; +import ru.otus.services.processors.*; +import ru.otus.services.menu.MenuOption; +import ru.otus.services.menu.MenuOptionsRegistryImpl; + + +import java.util.List; + +// OCP + ISP (AppSettings + IOService) + тесты +public class Main { + + public static void main(String[] args) { + var appSettings = new AppSettings(true, "dd.mm.YYYY HH:mm:ss"); + var ioService = new IOServiceStreams(System.out, System.in); + var applicationStopService = new ApplicationStopServiceImpl(ioService, appSettings); + var notesService = new NotesServiceImpl(); + var noteConverter = new NoteConverterImpl(appSettings); + + var showAllNotesMenuOption = new MenuOption(1, "Вывести все заметки"); + var addNewNoteMenuOption = new MenuOption(2, "Добавить заметку"); + var updateNoteMenuOption = new MenuOption(3, "Изменить заметку"); + var deleteNoteMenuOption = new MenuOption(4, "Удалить заметку"); + var stopApplicationMenuOption = new MenuOption(5, "Выйти"); + + var menuOptions = List.of(showAllNotesMenuOption, addNewNoteMenuOption, + updateNoteMenuOption, deleteNoteMenuOption, stopApplicationMenuOption + ); + var menuOptionsRegistry = new MenuOptionsRegistryImpl(menuOptions); + + var processors = List.of( + new ShowAllNotesSingleCommandProcessor(ioService, notesService, noteConverter, showAllNotesMenuOption), + new AddNewNoteSingleCommandProcessor(ioService, notesService, addNewNoteMenuOption), + new UpdateNoteSingleCommandProcessor(ioService, notesService, updateNoteMenuOption), + new DeleteNoteSingleCommandProcessor(ioService, notesService, deleteNoteMenuOption), + new StopApplicationSingleCommandProcessor(applicationStopService, stopApplicationMenuOption) + ); + + var menuCommandsProcessor = new MenuCommandsProcessorImpl(processors); + + new ApplicationRunner(ioService, applicationStopService, menuOptionsRegistry, menuCommandsProcessor) + .run(); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/AppSettings.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/AppSettings.java new file mode 100644 index 00000000..15d18038 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/AppSettings.java @@ -0,0 +1,21 @@ +package ru.otus.config; + +public class AppSettings implements DateTimeFormatProvider, ApplicationStopServiceSettingsProvider{ + private final boolean confirmExit; + private final String dateTimeFormat; + + public AppSettings(boolean confirmExit, String dateTimeFormat) { + this.confirmExit = confirmExit; + this.dateTimeFormat = dateTimeFormat; + } + + @Override + public boolean isConfirmExit() { + return confirmExit; + } + + @Override + public String getDateTimeFormat() { + return dateTimeFormat; + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/ApplicationStopServiceSettingsProvider.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/ApplicationStopServiceSettingsProvider.java new file mode 100644 index 00000000..fe5d2ed7 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/ApplicationStopServiceSettingsProvider.java @@ -0,0 +1,5 @@ +package ru.otus.config; + +public interface ApplicationStopServiceSettingsProvider { + boolean isConfirmExit(); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/DateTimeFormatProvider.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/DateTimeFormatProvider.java new file mode 100644 index 00000000..9f864dc7 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/config/DateTimeFormatProvider.java @@ -0,0 +1,5 @@ +package ru.otus.config; + +public interface DateTimeFormatProvider { + String getDateTimeFormat(); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuCommandProcessorNotFound.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuCommandProcessorNotFound.java new file mode 100644 index 00000000..b9b89316 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuCommandProcessorNotFound.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class MenuCommandProcessorNotFound extends RuntimeException { + public MenuCommandProcessorNotFound(String message) { + super(message); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java new file mode 100644 index 00000000..5fa79742 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/MenuItemIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class MenuItemIndexOutOfBoundsException extends IndexOutOfBoundsException { + public MenuItemIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java new file mode 100644 index 00000000..2c9592f6 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/exceptions/NoteIndexOutOfBoundsException.java @@ -0,0 +1,7 @@ +package ru.otus.exceptions; + +public class NoteIndexOutOfBoundsException extends IndexOutOfBoundsException { + public NoteIndexOutOfBoundsException(String s) { + super(s); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/model/Note.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/model/Note.java new file mode 100644 index 00000000..10d3b8ee --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/model/Note.java @@ -0,0 +1,53 @@ +package ru.otus.model; + +import java.time.LocalDateTime; +import java.util.UUID; + +public class Note { + private final String id; + private final LocalDateTime creationTime; + private final String text; + + public Note(String text) { + this.id = UUID.randomUUID().toString(); + this.creationTime = LocalDateTime.now(); + this.text = text; + } + + public Note(String id, String text) { + this.id = id; + this.creationTime = LocalDateTime.now(); + this.text = text; + } + + public Note(String id, LocalDateTime creationTime, String text) { + this.id = id; + this.creationTime = creationTime; + this.text = text; + } + + public static Note of(String text) { + return new Note(text); + } + + public static Note of(String id, String text) { + return new Note(id, text); + } + + public String getId() { + return id; + } + + public LocalDateTime getCreationTime() { + return creationTime; + } + + public String getText() { + return text; + } + + + public Note copy() { + return new Note(id, creationTime, text); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationRunner.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationRunner.java new file mode 100644 index 00000000..57a93b66 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationRunner.java @@ -0,0 +1,66 @@ +package ru.otus.services; + +import ru.otus.exceptions.MenuCommandProcessorNotFound; +import ru.otus.exceptions.MenuItemIndexOutOfBoundsException; +import ru.otus.exceptions.NoteIndexOutOfBoundsException; +import ru.otus.services.menu.MenuOption; +import ru.otus.services.menu.MenuOptionsRegistry; +import ru.otus.services.processors.MenuCommandsProcessor; + +import java.util.Comparator; + +public class ApplicationRunner { + private final IOService ioService; + private final ApplicationStopService applicationStopService; + private final MenuOptionsRegistry menuOptionsRegistry; + private final MenuCommandsProcessor commandsProcessor; + + + public ApplicationRunner(IOService ioService, + ApplicationStopService applicationStopService, + MenuOptionsRegistry menuOptionsRegistry, + MenuCommandsProcessor commandsProcessor) { + this.ioService = ioService; + this.applicationStopService = applicationStopService; + this.menuOptionsRegistry = menuOptionsRegistry; + this.commandsProcessor = commandsProcessor; + } + + public void run() { + while (applicationStopService.isApplicationRunning()) { + outputMenu(); + try { + var selectedMenuItem = readSelectedOptionNumber(); + processMenuCommand(selectedMenuItem); + + } catch (NumberFormatException e) { + ioService.outputString("Ошибка при вводе числа"); + } catch (MenuItemIndexOutOfBoundsException e) { + ioService.outputString("Введен неверный номер опции"); + } catch (NoteIndexOutOfBoundsException e) { + ioService.outputString("Введен несуществующий номер заметки"); + } catch (MenuCommandProcessorNotFound e) { + ioService.outputString("Не найден обработчик для выбранного пункта меню"); + } + } + } + + private void outputMenu() { + ioService.outputString("Выберите одно из следующих действий..."); + menuOptionsRegistry.getAvailableMenuOptions().stream() + .sorted(Comparator.comparingInt(MenuOption::getId)) + .map(m -> m.getId() + ". " + m.getDescription()) + .forEach(ioService::outputString); + } + + private void processMenuCommand(int selectedMenuItemId) { + var selectedMenuOption = menuOptionsRegistry.getMenuOptionById(selectedMenuItemId) + .orElseThrow(() -> new MenuItemIndexOutOfBoundsException("Given menu item index is out of range")); + + commandsProcessor.processMenuCommand(selectedMenuOption); + } + + private int readSelectedOptionNumber() { + return ioService.readInt(); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopService.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopService.java new file mode 100644 index 00000000..31d612f9 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopService.java @@ -0,0 +1,6 @@ +package ru.otus.services; + +public interface ApplicationStopService { + boolean isApplicationRunning(); + void stopApplication(); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java new file mode 100644 index 00000000..efd4d67c --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/ApplicationStopServiceImpl.java @@ -0,0 +1,36 @@ +package ru.otus.services; + +import ru.otus.config.ApplicationStopServiceSettingsProvider; +import ru.otus.services.processors.InputService; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class ApplicationStopServiceImpl implements ApplicationStopService { + + private final InputService inputService; + private final ApplicationStopServiceSettingsProvider settingsProvider; + private final AtomicBoolean executionFlag; + + public ApplicationStopServiceImpl(InputService inputService, + ApplicationStopServiceSettingsProvider settingsProvider) { + this.inputService = inputService; + this.settingsProvider = settingsProvider; + this.executionFlag = new AtomicBoolean(true); + } + + @Override + public boolean isApplicationRunning() { + return executionFlag.get(); + } + + @Override + public void stopApplication() { + if (settingsProvider.isConfirmExit()) { + var exitConfirmation = inputService.readStringWithPrompt("Действительно выйти? (да/нет)"); + if (exitConfirmation.equalsIgnoreCase("нет")) { + return; + } + } + executionFlag.set(false); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOService.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOService.java new file mode 100644 index 00000000..5e8cd764 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOService.java @@ -0,0 +1,9 @@ +package ru.otus.services; + +import ru.otus.services.processors.InputService; +import ru.otus.services.processors.OutputService; + +public interface IOService extends InputService, OutputService { + + +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOServiceStreams.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOServiceStreams.java new file mode 100644 index 00000000..ca7dff21 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/IOServiceStreams.java @@ -0,0 +1,37 @@ +package ru.otus.services; + +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Scanner; + +public class IOServiceStreams implements IOService { + private final PrintStream output; + private final Scanner input; + + public IOServiceStreams(PrintStream outputStream, InputStream inputStream) { + output = outputStream; + input = new Scanner(inputStream); + } + + @Override + public void outputString(String s){ + output.println(s); + } + + @Override + public int readInt(){ + return Integer.parseInt(input.nextLine()); + } + + @Override + public int readIntWithPrompt(String prompt){ + outputString(prompt); + return Integer.parseInt(input.nextLine()); + } + + @Override + public String readStringWithPrompt(String prompt){ + outputString(prompt); + return input.nextLine(); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverter.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverter.java new file mode 100644 index 00000000..7dfe1e57 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverter.java @@ -0,0 +1,7 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +public interface NoteConverter { + String convertNoteToString(int noteNumber, Note note); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverterImpl.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverterImpl.java new file mode 100644 index 00000000..5ff2c79f --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NoteConverterImpl.java @@ -0,0 +1,20 @@ +package ru.otus.services; + +import ru.otus.config.DateTimeFormatProvider; +import ru.otus.model.Note; + +import java.time.format.DateTimeFormatter; + +public class NoteConverterImpl implements NoteConverter { + private final DateTimeFormatProvider dateTimeFormatProvider; + + public NoteConverterImpl(DateTimeFormatProvider dateTimeFormatProvider) { + this.dateTimeFormatProvider = dateTimeFormatProvider; + } + + @Override + public String convertNoteToString(int noteNumber, Note note) { + var dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimeFormatProvider.getDateTimeFormat()); + return noteNumber + " | " + dateTimeFormatter.format(note.getCreationTime()) + " | " + note.getText(); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesService.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesService.java new file mode 100644 index 00000000..019c6cd7 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesService.java @@ -0,0 +1,13 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +import java.util.List; + +public interface NotesService { + List getAll(); + + void save(Note note); + + void remove(String id); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesServiceImpl.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesServiceImpl.java new file mode 100644 index 00000000..b8c15298 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/NotesServiceImpl.java @@ -0,0 +1,31 @@ +package ru.otus.services; + +import ru.otus.model.Note; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class NotesServiceImpl implements NotesService { + private final Map notes; + + public NotesServiceImpl() { + notes = new HashMap<>(); + } + + @Override + public List getAll() { + return notes.values().stream().map(Note::copy).collect(Collectors.toList()); + } + + @Override + public void save(Note note) { + notes.put(note.getId(), note); + } + + @Override + public void remove(String id) { + notes.remove(id); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOption.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOption.java new file mode 100644 index 00000000..2514200b --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOption.java @@ -0,0 +1,34 @@ +package ru.otus.services.menu; + +public class MenuOption { + private final int id; + private final String description; + + public MenuOption(int id, String description) { + this.id = id; + this.description = description; + } + + public int getId() { + return id; + } + + public String getDescription() { + return description; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MenuOption that = (MenuOption) o; + + return id == that.id; + } + + @Override + public int hashCode() { + return id; + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistry.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistry.java new file mode 100644 index 00000000..cd5c86cb --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistry.java @@ -0,0 +1,9 @@ +package ru.otus.services.menu; + +import java.util.List; +import java.util.Optional; + +public interface MenuOptionsRegistry { + List getAvailableMenuOptions(); + Optional getMenuOptionById(int id); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistryImpl.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistryImpl.java new file mode 100644 index 00000000..30fca79d --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/menu/MenuOptionsRegistryImpl.java @@ -0,0 +1,26 @@ +package ru.otus.services.menu; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class MenuOptionsRegistryImpl implements MenuOptionsRegistry { + private final Map options; + + public MenuOptionsRegistryImpl(List options) { + this.options = options.stream() + .collect(Collectors.toUnmodifiableMap(MenuOption::getId, Function.identity())); + } + + @Override + public List getAvailableMenuOptions() { + return options.values().stream().collect(Collectors.toUnmodifiableList()); + } + + @Override + public Optional getMenuOptionById(int id) { + return Optional.ofNullable(options.get(id)); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessor.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessor.java new file mode 100644 index 00000000..7649900f --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessor.java @@ -0,0 +1,30 @@ +package ru.otus.services.processors; + +import ru.otus.model.Note; +import ru.otus.services.NotesService; +import ru.otus.services.menu.MenuOption; + +public class AddNewNoteSingleCommandProcessor implements MenuSingleCommandProcessor { + private final MenuOption processedCommandOption; + private final InputService inputService; + private final NotesService notesService; + + public AddNewNoteSingleCommandProcessor(InputService inputService, NotesService notesService, + MenuOption processedCommandOption) { + this.inputService = inputService; + this.notesService = notesService; + this.processedCommandOption = processedCommandOption; + } + + @Override + public void processCommand() { + var noteText = inputService.readStringWithPrompt("Введите текст заметки..."); + notesService.save(Note.of(noteText)); + + } + + @Override + public MenuOption getProcessedCommandOption() { + return processedCommandOption; + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/DeleteNoteSingleCommandProcessor.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/DeleteNoteSingleCommandProcessor.java new file mode 100644 index 00000000..43898f61 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/DeleteNoteSingleCommandProcessor.java @@ -0,0 +1,37 @@ +package ru.otus.services.processors; + +import ru.otus.services.NotesService; +import ru.otus.services.menu.MenuOption; + + +import static ru.otus.services.processors.utils.NotesListUtil.checkNoteNumber; + +public class DeleteNoteSingleCommandProcessor implements MenuSingleCommandProcessor { + private final MenuOption processedCommandOption; + private final InputService inputService; + private final NotesService notesService; + + public DeleteNoteSingleCommandProcessor(InputService inputService, NotesService notesService, + MenuOption processedCommandOption) { + this.inputService = inputService; + this.notesService = notesService; + this.processedCommandOption = processedCommandOption; + } + + @Override + public void processCommand() { + var notes = notesService.getAll(); + + var deletedNoteNumber = inputService.readIntWithPrompt("Введите номер удаляемой заметки..."); + checkNoteNumber(deletedNoteNumber, notes.size()); + + var updatedNote = notes.get(deletedNoteNumber - 1); + notesService.remove(updatedNote.getId()); + } + + @Override + public MenuOption getProcessedCommandOption() { + return processedCommandOption; + } + +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/InputService.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/InputService.java new file mode 100644 index 00000000..52079551 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/InputService.java @@ -0,0 +1,9 @@ +package ru.otus.services.processors; + +public interface InputService { + int readInt(); + + int readIntWithPrompt(String prompt); + + String readStringWithPrompt(String prompt); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessor.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessor.java new file mode 100644 index 00000000..68f7f77a --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessor.java @@ -0,0 +1,7 @@ +package ru.otus.services.processors; + +import ru.otus.services.menu.MenuOption; + +public interface MenuCommandsProcessor { + void processMenuCommand(MenuOption selectedMenuOption); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessorImpl.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessorImpl.java new file mode 100644 index 00000000..495841cf --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuCommandsProcessorImpl.java @@ -0,0 +1,27 @@ +package ru.otus.services.processors; + +import ru.otus.exceptions.MenuCommandProcessorNotFound; +import ru.otus.services.menu.MenuOption; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class MenuCommandsProcessorImpl implements MenuCommandsProcessor { + private final Map processors; + + public MenuCommandsProcessorImpl(List processors) { + this.processors = processors.stream() + .collect(Collectors.toMap(MenuSingleCommandProcessor::getProcessedCommandOption, Function.identity())); + } + + @Override + public void processMenuCommand(MenuOption selectedMenuOption) { + var commandProcessor = processors.get(selectedMenuOption); + if (commandProcessor == null) { + throw new MenuCommandProcessorNotFound("Menu command processor for given option does not registered"); + } + commandProcessor.processCommand(); + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuSingleCommandProcessor.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuSingleCommandProcessor.java new file mode 100644 index 00000000..fb5f7245 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/MenuSingleCommandProcessor.java @@ -0,0 +1,8 @@ +package ru.otus.services.processors; + +import ru.otus.services.menu.MenuOption; + +public interface MenuSingleCommandProcessor { + void processCommand(); + MenuOption getProcessedCommandOption(); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/OutputService.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/OutputService.java new file mode 100644 index 00000000..dd68ad88 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/OutputService.java @@ -0,0 +1,5 @@ +package ru.otus.services.processors; + +public interface OutputService { + void outputString(String s); +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/ShowAllNotesSingleCommandProcessor.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/ShowAllNotesSingleCommandProcessor.java new file mode 100644 index 00000000..8d902e69 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/ShowAllNotesSingleCommandProcessor.java @@ -0,0 +1,38 @@ +package ru.otus.services.processors; + +import ru.otus.services.NoteConverter; +import ru.otus.services.NotesService; +import ru.otus.services.menu.MenuOption; + +import java.util.stream.IntStream; + +public class ShowAllNotesSingleCommandProcessor implements MenuSingleCommandProcessor { + private final MenuOption processedCommandOption; + + private final OutputService outputService; + private final NotesService notesService; + private final NoteConverter noteConverter; + + public ShowAllNotesSingleCommandProcessor(OutputService outputService, NotesService notesService, + NoteConverter noteConverter, MenuOption processedCommandOption) { + this.outputService = outputService; + this.notesService = notesService; + this.noteConverter = noteConverter; + this.processedCommandOption = processedCommandOption; + } + + @Override + public void processCommand() { + var notes = notesService.getAll(); + outputService.outputString("Заметки:"); + IntStream.range(1, notes.size() + 1) + .mapToObj(k -> noteConverter.convertNoteToString(k, notes.get(k - 1))) + .forEach(outputService::outputString); + outputService.outputString(""); + } + + @Override + public MenuOption getProcessedCommandOption() { + return processedCommandOption; + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/StopApplicationSingleCommandProcessor.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/StopApplicationSingleCommandProcessor.java new file mode 100644 index 00000000..4fbef62c --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/StopApplicationSingleCommandProcessor.java @@ -0,0 +1,25 @@ +package ru.otus.services.processors; + +import ru.otus.services.ApplicationStopService; +import ru.otus.services.menu.MenuOption; + +public class StopApplicationSingleCommandProcessor implements MenuSingleCommandProcessor { + private final MenuOption processedCommandOption; + private final ApplicationStopService applicationStopService; + + public StopApplicationSingleCommandProcessor(ApplicationStopService applicationStopService, + MenuOption processedCommandOption) { + this.applicationStopService = applicationStopService; + this.processedCommandOption = processedCommandOption; + } + + @Override + public void processCommand() { + applicationStopService.stopApplication(); + } + + @Override + public MenuOption getProcessedCommandOption() { + return processedCommandOption; + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/UpdateNoteSingleCommandProcessor.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/UpdateNoteSingleCommandProcessor.java new file mode 100644 index 00000000..85116a15 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/UpdateNoteSingleCommandProcessor.java @@ -0,0 +1,41 @@ +package ru.otus.services.processors; + +import ru.otus.model.Note; +import ru.otus.services.menu.MenuOption; +import ru.otus.services.NotesService; + +import java.util.List; + +import static ru.otus.services.processors.utils.NotesListUtil.checkNoteNumber; + +public class UpdateNoteSingleCommandProcessor implements MenuSingleCommandProcessor { + private final MenuOption processedCommandOption; + private final InputService inputService; + private final NotesService notesService; + + public UpdateNoteSingleCommandProcessor(InputService inputService, NotesService notesService, + MenuOption processedCommandOption) { + this.inputService = inputService; + this.notesService = notesService; + this.processedCommandOption = processedCommandOption; + } + + @Override + public void processCommand() { + var notes = notesService.getAll(); + + var updatedNoteNumber = inputService.readIntWithPrompt("Введите номер изменяемой заметки..."); + checkNoteNumber(updatedNoteNumber, notes.size()); + + var noteText = inputService.readStringWithPrompt("Введите текст заметки..."); + + var updatedNote = notes.get(updatedNoteNumber - 1); + notesService.save(Note.of(updatedNote.getId(), noteText)); } + + @Override + public MenuOption getProcessedCommandOption() { + return processedCommandOption; + } + + +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/utils/NotesListUtil.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/utils/NotesListUtil.java new file mode 100644 index 00000000..0f19e3cf --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/main/java/ru/otus/services/processors/utils/NotesListUtil.java @@ -0,0 +1,11 @@ +package ru.otus.services.processors.utils; + +import ru.otus.exceptions.NoteIndexOutOfBoundsException; + +public class NotesListUtil { + public static void checkNoteNumber(int noteNumber, int notesCount) { + if (noteNumber <= 0 || noteNumber > notesCount) { + throw new NoteIndexOutOfBoundsException("Given number of note is out of range"); + } + } +} diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/ApplicationStopServiceImplTest.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/ApplicationStopServiceImplTest.java new file mode 100644 index 00000000..71ddf850 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/ApplicationStopServiceImplTest.java @@ -0,0 +1,33 @@ +package ru.otus.services; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import ru.otus.config.ApplicationStopServiceSettingsProvider; +import ru.otus.services.processors.InputService; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.*; + +@DisplayName("Сервис остановки приложения ") +class ApplicationStopServiceImplTest { + + @DisplayName("должен возвращать корректный статус работы приложения") + @ParameterizedTest(name = "остановить приложение: {0}, ожидаемый результат: {1}") + @CsvSource({"false, true", "true, false"}) + void shouldReturnCorrectApplicationExecutionStatus(boolean shouldStopApplication, boolean expectedStatus) { + var inputService = mock(InputService.class); + var settingsProvider = mock(ApplicationStopServiceSettingsProvider.class); + given(settingsProvider.isConfirmExit()).willReturn(false); + var applicationStopService = new ApplicationStopServiceImpl(inputService, settingsProvider); + + if (shouldStopApplication) { + applicationStopService.stopApplication(); + verify(settingsProvider, times(1)).isConfirmExit(); + } + var actualStatus = applicationStopService.isApplicationRunning(); + assertThat(actualStatus).isEqualTo(expectedStatus); + verify(inputService, never()).readStringWithPrompt(any()); + } +} \ No newline at end of file diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/menu/MenuOptionsRegistryImplTest.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/menu/MenuOptionsRegistryImplTest.java new file mode 100644 index 00000000..21c13cd5 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/menu/MenuOptionsRegistryImplTest.java @@ -0,0 +1,44 @@ +package ru.otus.services.menu; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("Реестр опций меню ") +class MenuOptionsRegistryImplTest { + + private List options; + private MenuOptionsRegistryImpl menuOptionsRegistry; + + @BeforeEach + void setUp() { + options = List.of(new MenuOption(1, "opt1"), new MenuOption(2, "opt2")); + menuOptionsRegistry = new MenuOptionsRegistryImpl(options); + } + + @DisplayName("должен возвращать список ожидаемых опций ") + @Test + void shouldReturnExpectedAvailableMenuOptions() { + var actualOptions = menuOptionsRegistry.getAvailableMenuOptions(); + assertThat(actualOptions) + .usingRecursiveFieldByFieldElementComparator() + .containsExactlyInAnyOrderElementsOf(options); + } + + // Обратить внимание на работу с Optional + @DisplayName("должен корректно возвращать опцию меню по ее идентификатору ") + @Test + void shouldReturnExpectedMenuOptionById() { + var expectedOption = options.get(0); + var actualOption = menuOptionsRegistry.getMenuOptionById(expectedOption.getId()); + assertThat(actualOption).isNotEmpty() + .get() + .usingRecursiveComparison() + .isEqualTo(expectedOption); + } +} \ No newline at end of file diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessorTest.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessorTest.java new file mode 100644 index 00000000..d5f5b32d --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/AddNewNoteSingleCommandProcessorTest.java @@ -0,0 +1,59 @@ +package ru.otus.services.processors; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import ru.otus.model.Note; +import ru.otus.services.NotesService; +import ru.otus.services.menu.MenuOption; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@DisplayName("Процессор команды добавления новой заметки ") +@ExtendWith(MockitoExtension.class) +class AddNewNoteSingleCommandProcessorTest { + + @Mock + private MenuOption processedCommandOption; + + @Mock + private InputService inputService; + + @Mock + private NotesService notesService; + + @InjectMocks + private AddNewNoteSingleCommandProcessor processor; + + @DisplayName("должен корректно добавлять новой заметки ") + @Test + void shouldCorrectAddExpectedNoteUseExpectedServicesMethods() { + var expectedNoteText = "Expected Note Text"; + given(inputService.readStringWithPrompt(anyString())) + .willReturn(expectedNoteText); + + processor.processCommand(); + + verify(inputService, times(1)).readStringWithPrompt(any()); + + var captor = ArgumentCaptor.forClass(Note.class); + verify(notesService).save(captor.capture()); + var actualNote = captor.getValue(); + assertThat(actualNote).extracting(Note::getText).isEqualTo(expectedNoteText); + } + + @DisplayName("должен возвращает ожидаемый тип обрабатываемой команды") + @Test + void shouldReturnExpectedProcessedCommandOption() { + assertThat(processor.getProcessedCommandOption()).isEqualTo(processedCommandOption); + } +} \ No newline at end of file diff --git a/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/MenuCommandsProcessorImplTest.java b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/MenuCommandsProcessorImplTest.java new file mode 100644 index 00000000..0d5c0238 --- /dev/null +++ b/2023-01/spring-03-arch/solution10_ocp_isp/src/test/java/ru/otus/services/processors/MenuCommandsProcessorImplTest.java @@ -0,0 +1,55 @@ +package ru.otus.services.processors; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import ru.otus.exceptions.MenuCommandProcessorNotFound; +import ru.otus.services.menu.MenuOption; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.*; + +@DisplayName("Процессор команд меню ") +class MenuCommandsProcessorImplTest { + + private List singleCommandProcessors; + private MenuCommandsProcessorImpl processor; + + @BeforeEach + void setUp() { + singleCommandProcessors = prepareProcessorsMocks(); + processor = new MenuCommandsProcessorImpl(singleCommandProcessors); + } + + @DisplayName("должен корректно обрабатывать команду если для нее есть процессор") + @Test + void shouldCorrectProcessMenuCommandWhenProcessorForGivenCommandExists() { + for (var singleCommandProcessor : singleCommandProcessors) { + processor.processMenuCommand(singleCommandProcessor.getProcessedCommandOption()); + verify(singleCommandProcessor, times(1)).processCommand(); + } + } + + @DisplayName("должен кидать ожидаемое исключение если процессор для заданной команды отсутствует") + @Test + void shouldThrowExpectedExceptionWhenProcessorForGivenCommandDoesNotExists() { + var commandOptionWithNotExistingProcessor = new MenuOption(4, "opt4"); + assertThatCode(() -> processor.processMenuCommand(commandOptionWithNotExistingProcessor)) + .isInstanceOf(MenuCommandProcessorNotFound.class); + } + + private static List prepareProcessorsMocks() { + List processors = new ArrayList<>(3); + for (int i = 1; i < 4; i++) { + var opt = new MenuOption(i, "opt" + i); + var singleCommandProcessor = mock(MenuSingleCommandProcessor.class); + given(singleCommandProcessor.getProcessedCommandOption()).willReturn(opt); + processors.add(singleCommandProcessor); + } + return processors; + } +} \ No newline at end of file