From 962e8898e02d8df0bc94d66fc72d94f000803b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Thu, 23 May 2024 17:57:46 +0300 Subject: [PATCH] refactor: rename and delete some patterns (#2970) --- .../README.md | 0 ...-query-responsibility-segregation.urm.puml | 136 +++++++ .../etc/cqrs.png | Bin .../etc/cqrs.ucls | 0 .../etc/cqrs.urm.puml | 0 .../pom.xml | 2 +- .../main/java/com/iluwatar/cqrs/app/App.java | 0 .../cqrs/commandes/CommandService.java | 0 .../cqrs/commandes/CommandServiceImpl.java | 0 .../iluwatar/cqrs/constants/AppConstants.java | 0 .../iluwatar/cqrs/domain/model/Author.java | 0 .../com/iluwatar/cqrs/domain/model/Book.java | 0 .../java/com/iluwatar/cqrs/dto/Author.java | 0 .../main/java/com/iluwatar/cqrs/dto/Book.java | 0 .../iluwatar/cqrs/queries/QueryService.java | 0 .../cqrs/queries/QueryServiceImpl.java | 0 .../com/iluwatar/cqrs/util/HibernateUtil.java | 0 .../src/main/resources/hibernate.cfg.xml | 0 .../src/main/resources/logback.xml | 0 .../com/iluwatar/cqrs/IntegrationTest.java | 0 .../src/test/resources/hibernate.cfg.xml | 0 .../src/test/resources/logback.xml | 0 .../com/iluwatar/commander/RetryParams.java | 24 ++ .../com/iluwatar/commander/TimeLimits.java | 24 ++ .../README.md | 360 +++++++++--------- .../etc/crtp.png | Bin .../etc/crtp.urm.puml | 0 ...iously-recurring-template-pattern.urm.puml | 2 + .../pom.xml | 128 +++---- .../src/main/java/crtp/App.java | 0 .../src/main/java/crtp/Fighter.java | 72 ++-- .../java/crtp/MmaBantamweightFighter.java | 70 ++-- .../src/main/java/crtp/MmaFighter.java | 98 ++--- .../main/java/crtp/MmaHeavyweightFighter.java | 72 ++-- .../main/java/crtp/MmaLightweightFighter.java | 72 ++-- .../src/test/java/crtp/AppTest.java | 0 .../src/test/java/crtp/FightTest.java | 148 +++---- {dao => data-access-object}/README.md | 0 {dao => data-access-object}/etc/dao.png | Bin {dao => data-access-object}/etc/dao.ucls | 0 {dao => data-access-object}/etc/dao.urm.puml | 0 .../etc/data-access-object.urm.puml | 69 ++++ {dao => data-access-object}/pom.xml | 2 +- .../src/main/java/com/iluwatar/dao/App.java | 0 .../com/iluwatar/dao/CustomException.java | 80 ++-- .../main/java/com/iluwatar/dao/Customer.java | 0 .../java/com/iluwatar/dao/CustomerDao.java | 0 .../com/iluwatar/dao/CustomerSchemaSql.java | 0 .../java/com/iluwatar/dao/DbCustomerDao.java | 0 .../com/iluwatar/dao/InMemoryCustomerDao.java | 0 .../test/java/com/iluwatar/dao/AppTest.java | 0 .../java/com/iluwatar/dao/CustomerTest.java | 0 .../com/iluwatar/dao/DbCustomerDaoTest.java | 0 .../iluwatar/dao/InMemoryCustomerDaoTest.java | 0 master-worker/etc/master-worker.urm.puml | 78 ++++ module/.gitignore | 2 - module/README.md | 163 -------- module/etc/module.png | Bin 18027 -> 0 bytes module/etc/module.ucls | 69 ---- module/etc/module.urm.puml | 43 --- module/pom.xml | 62 --- .../main/java/com/iluwatar/module/App.java | 95 ----- .../iluwatar/module/ConsoleLoggerModule.java | 111 ------ .../com/iluwatar/module/FileLoggerModule.java | 119 ------ .../java/com/iluwatar/module/AppTest.java | 42 -- .../iluwatar/module/FileLoggerModuleTest.java | 174 --------- pom.xml | 9 +- priority-queue/README.md | 227 ----------- priority-queue/etc/priority-queue.urm.png | Bin 52777 -> 0 bytes priority-queue/etc/priority-queue.urm.puml | 54 --- priority-queue/pom.xml | 62 --- .../iluwatar/priority/queue/Application.java | 60 --- .../com/iluwatar/priority/queue/Message.java | 52 --- .../priority/queue/PriorityMessageQueue.java | 178 --------- .../iluwatar/priority/queue/QueueManager.java | 59 --- .../com/iluwatar/priority/queue/Worker.java | 64 ---- .../queue/PriorityMessageQueueTest.java | 75 ---- .../priority/queue/QueueManagerTest.java | 55 --- reader-writer-lock/README.md | 192 ---------- reader-writer-lock/etc/reader-writer-lock.png | Bin 39623 -> 0 bytes .../etc/reader-writer-lock.ucls | 86 ----- .../etc/reader-writer-lock.urm.puml | 65 ---- reader-writer-lock/pom.xml | 67 ---- .../com/iluwatar/reader/writer/lock/App.java | 102 ----- .../iluwatar/reader/writer/lock/Reader.java | 86 ----- .../reader/writer/lock/ReaderWriterLock.java | 217 ----------- .../iluwatar/reader/writer/lock/Writer.java | 87 ----- .../iluwatar/reader/writer/lock/AppTest.java | 41 -- .../writer/lock/ReaderAndWriterTest.java | 117 ------ .../reader/writer/lock/ReaderTest.java | 88 ----- .../reader/writer/lock/WriterTest.java | 89 ----- .../writer/lock/utils/InMemoryAppender.java | 58 --- .../serializedentity/CountryTest.java | 7 + type-object/etc/type-object.urm.puml | 77 ++++ 94 files changed, 972 insertions(+), 3619 deletions(-) rename {cqrs => command-query-responsibility-segregation}/README.md (100%) create mode 100644 command-query-responsibility-segregation/etc/command-query-responsibility-segregation.urm.puml rename {cqrs => command-query-responsibility-segregation}/etc/cqrs.png (100%) rename {cqrs => command-query-responsibility-segregation}/etc/cqrs.ucls (100%) rename {cqrs => command-query-responsibility-segregation}/etc/cqrs.urm.puml (100%) rename {cqrs => command-query-responsibility-segregation}/pom.xml (97%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/app/App.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/domain/model/Author.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/domain/model/Book.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/dto/Author.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/dto/Book.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/queries/QueryService.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/resources/hibernate.cfg.xml (100%) rename {cqrs => command-query-responsibility-segregation}/src/main/resources/logback.xml (100%) rename {cqrs => command-query-responsibility-segregation}/src/test/java/com/iluwatar/cqrs/IntegrationTest.java (100%) rename {cqrs => command-query-responsibility-segregation}/src/test/resources/hibernate.cfg.xml (100%) rename {cqrs => command-query-responsibility-segregation}/src/test/resources/logback.xml (100%) rename {crtp => curiously-recurring-template-pattern}/README.md (97%) rename {crtp => curiously-recurring-template-pattern}/etc/crtp.png (100%) rename {crtp => curiously-recurring-template-pattern}/etc/crtp.urm.puml (100%) create mode 100644 curiously-recurring-template-pattern/etc/curiously-recurring-template-pattern.urm.puml rename {crtp => curiously-recurring-template-pattern}/pom.xml (96%) rename {crtp => curiously-recurring-template-pattern}/src/main/java/crtp/App.java (100%) rename {crtp => curiously-recurring-template-pattern}/src/main/java/crtp/Fighter.java (97%) rename {crtp => curiously-recurring-template-pattern}/src/main/java/crtp/MmaBantamweightFighter.java (97%) rename {crtp => curiously-recurring-template-pattern}/src/main/java/crtp/MmaFighter.java (97%) rename {crtp => curiously-recurring-template-pattern}/src/main/java/crtp/MmaHeavyweightFighter.java (97%) rename {crtp => curiously-recurring-template-pattern}/src/main/java/crtp/MmaLightweightFighter.java (97%) rename {crtp => curiously-recurring-template-pattern}/src/test/java/crtp/AppTest.java (100%) rename {crtp => curiously-recurring-template-pattern}/src/test/java/crtp/FightTest.java (97%) rename {dao => data-access-object}/README.md (100%) rename {dao => data-access-object}/etc/dao.png (100%) rename {dao => data-access-object}/etc/dao.ucls (100%) rename {dao => data-access-object}/etc/dao.urm.puml (100%) create mode 100644 data-access-object/etc/data-access-object.urm.puml rename {dao => data-access-object}/pom.xml (98%) rename {dao => data-access-object}/src/main/java/com/iluwatar/dao/App.java (100%) rename {dao => data-access-object}/src/main/java/com/iluwatar/dao/CustomException.java (97%) rename {dao => data-access-object}/src/main/java/com/iluwatar/dao/Customer.java (100%) rename {dao => data-access-object}/src/main/java/com/iluwatar/dao/CustomerDao.java (100%) rename {dao => data-access-object}/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java (100%) rename {dao => data-access-object}/src/main/java/com/iluwatar/dao/DbCustomerDao.java (100%) rename {dao => data-access-object}/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java (100%) rename {dao => data-access-object}/src/test/java/com/iluwatar/dao/AppTest.java (100%) rename {dao => data-access-object}/src/test/java/com/iluwatar/dao/CustomerTest.java (100%) rename {dao => data-access-object}/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java (100%) rename {dao => data-access-object}/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java (100%) create mode 100644 master-worker/etc/master-worker.urm.puml delete mode 100644 module/.gitignore delete mode 100644 module/README.md delete mode 100644 module/etc/module.png delete mode 100644 module/etc/module.ucls delete mode 100644 module/etc/module.urm.puml delete mode 100644 module/pom.xml delete mode 100644 module/src/main/java/com/iluwatar/module/App.java delete mode 100644 module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java delete mode 100644 module/src/main/java/com/iluwatar/module/FileLoggerModule.java delete mode 100644 module/src/test/java/com/iluwatar/module/AppTest.java delete mode 100644 module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java delete mode 100644 priority-queue/README.md delete mode 100644 priority-queue/etc/priority-queue.urm.png delete mode 100644 priority-queue/etc/priority-queue.urm.puml delete mode 100644 priority-queue/pom.xml delete mode 100644 priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java delete mode 100644 priority-queue/src/main/java/com/iluwatar/priority/queue/Message.java delete mode 100644 priority-queue/src/main/java/com/iluwatar/priority/queue/PriorityMessageQueue.java delete mode 100644 priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java delete mode 100644 priority-queue/src/main/java/com/iluwatar/priority/queue/Worker.java delete mode 100644 priority-queue/src/test/java/com/iluwatar/priority/queue/PriorityMessageQueueTest.java delete mode 100644 priority-queue/src/test/java/com/iluwatar/priority/queue/QueueManagerTest.java delete mode 100644 reader-writer-lock/README.md delete mode 100644 reader-writer-lock/etc/reader-writer-lock.png delete mode 100644 reader-writer-lock/etc/reader-writer-lock.ucls delete mode 100644 reader-writer-lock/etc/reader-writer-lock.urm.puml delete mode 100644 reader-writer-lock/pom.xml delete mode 100644 reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java delete mode 100644 reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java delete mode 100644 reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java delete mode 100644 reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java delete mode 100644 reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java delete mode 100644 reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderAndWriterTest.java delete mode 100644 reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderTest.java delete mode 100644 reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/WriterTest.java delete mode 100644 reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java create mode 100644 type-object/etc/type-object.urm.puml diff --git a/cqrs/README.md b/command-query-responsibility-segregation/README.md similarity index 100% rename from cqrs/README.md rename to command-query-responsibility-segregation/README.md diff --git a/command-query-responsibility-segregation/etc/command-query-responsibility-segregation.urm.puml b/command-query-responsibility-segregation/etc/command-query-responsibility-segregation.urm.puml new file mode 100644 index 000000000..aef8eef5c --- /dev/null +++ b/command-query-responsibility-segregation/etc/command-query-responsibility-segregation.urm.puml @@ -0,0 +1,136 @@ +@startuml +package com.iluwatar.cqrs.util { + class HibernateUtil { + - LOGGER : Logger {static} + - SESSIONFACTORY : SessionFactory {static} + + HibernateUtil() + - buildSessionFactory() : SessionFactory {static} + + getSessionFactory() : SessionFactory {static} + } +} +package com.iluwatar.cqrs.app { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.cqrs.dto { + class Author { + - email : String + - name : String + - username : String + + Author() + + Author(name : String, email : String, username : String) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getEmail() : String + + getName() : String + + getUsername() : String + + hashCode() : int + + toString() : String + } + class Book { + - price : double + - title : String + + Book() + + Book(title : String, price : double) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getPrice() : double + + getTitle() : String + + hashCode() : int + + toString() : String + } +} +package com.iluwatar.cqrs.commandes { + interface CommandService { + + authorCreated(String, String, String) {abstract} + + authorEmailUpdated(String, String) {abstract} + + authorNameUpdated(String, String) {abstract} + + authorUsernameUpdated(String, String) {abstract} + + bookAddedToAuthor(String, double, String) {abstract} + + bookPriceUpdated(String, double) {abstract} + + bookTitleUpdated(String, String) {abstract} + } + class CommandServiceImpl { + - sessionFactory : SessionFactory + + CommandServiceImpl() + + authorCreated(username : String, name : String, email : String) + + authorEmailUpdated(username : String, email : String) + + authorNameUpdated(username : String, name : String) + + authorUsernameUpdated(oldUsername : String, newUsername : String) + + bookAddedToAuthor(title : String, price : double, username : String) + + bookPriceUpdated(title : String, price : double) + + bookTitleUpdated(oldTitle : String, newTitle : String) + - getAuthorByUsername(username : String) : Author + - getBookByTitle(title : String) : Book + } +} +package com.iluwatar.cqrs.queries { + interface QueryService { + + getAuthorBooks(String) : List {abstract} + + getAuthorBooksCount(String) : BigInteger {abstract} + + getAuthorByUsername(String) : Author {abstract} + + getAuthorsCount() : BigInteger {abstract} + + getBook(String) : Book {abstract} + } + class QueryServiceImpl { + - sessionFactory : SessionFactory + + QueryServiceImpl() + + getAuthorBooks(username : String) : List + + getAuthorBooksCount(username : String) : BigInteger + + getAuthorByUsername(username : String) : Author + + getAuthorsCount() : BigInteger + + getBook(title : String) : Book + } +} +package com.iluwatar.cqrs.constants { + class AppConstants { + + E_EVANS : String {static} + + J_BLOCH : String {static} + + M_FOWLER : String {static} + + USER_NAME : String {static} + + AppConstants() + } +} +package com.iluwatar.cqrs.domain.model { + class Author { + - email : String + - id : long + - name : String + - username : String + # Author() + + Author(username : String, name : String, email : String) + + getEmail() : String + + getId() : long + + getName() : String + + getUsername() : String + + setEmail(email : String) + + setId(id : long) + + setName(name : String) + + setUsername(username : String) + + toString() : String + } + class Book { + - author : Author + - id : long + - price : double + - title : String + # Book() + + Book(title : String, price : double, author : Author) + + getAuthor() : Author + + getId() : long + + getPrice() : double + + getTitle() : String + + setAuthor(author : Author) + + setId(id : long) + + setPrice(price : double) + + setTitle(title : String) + + toString() : String + } +} +Book --> "-author" Author +CommandServiceImpl ..|> CommandService +QueryServiceImpl ..|> QueryService +@enduml \ No newline at end of file diff --git a/cqrs/etc/cqrs.png b/command-query-responsibility-segregation/etc/cqrs.png similarity index 100% rename from cqrs/etc/cqrs.png rename to command-query-responsibility-segregation/etc/cqrs.png diff --git a/cqrs/etc/cqrs.ucls b/command-query-responsibility-segregation/etc/cqrs.ucls similarity index 100% rename from cqrs/etc/cqrs.ucls rename to command-query-responsibility-segregation/etc/cqrs.ucls diff --git a/cqrs/etc/cqrs.urm.puml b/command-query-responsibility-segregation/etc/cqrs.urm.puml similarity index 100% rename from cqrs/etc/cqrs.urm.puml rename to command-query-responsibility-segregation/etc/cqrs.urm.puml diff --git a/cqrs/pom.xml b/command-query-responsibility-segregation/pom.xml similarity index 97% rename from cqrs/pom.xml rename to command-query-responsibility-segregation/pom.xml index ec78265cf..bc2659cdc 100644 --- a/cqrs/pom.xml +++ b/command-query-responsibility-segregation/pom.xml @@ -32,7 +32,7 @@ java-design-patterns 1.26.0-SNAPSHOT - cqrs + command-query-responsibility-segregation org.junit.jupiter diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/app/App.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/app/App.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/app/App.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Author.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Author.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Book.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Book.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Author.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Author.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Book.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Book.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryService.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryService.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryService.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryService.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java diff --git a/cqrs/src/main/resources/hibernate.cfg.xml b/command-query-responsibility-segregation/src/main/resources/hibernate.cfg.xml similarity index 100% rename from cqrs/src/main/resources/hibernate.cfg.xml rename to command-query-responsibility-segregation/src/main/resources/hibernate.cfg.xml diff --git a/cqrs/src/main/resources/logback.xml b/command-query-responsibility-segregation/src/main/resources/logback.xml similarity index 100% rename from cqrs/src/main/resources/logback.xml rename to command-query-responsibility-segregation/src/main/resources/logback.xml diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java b/command-query-responsibility-segregation/src/test/java/com/iluwatar/cqrs/IntegrationTest.java similarity index 100% rename from cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java rename to command-query-responsibility-segregation/src/test/java/com/iluwatar/cqrs/IntegrationTest.java diff --git a/cqrs/src/test/resources/hibernate.cfg.xml b/command-query-responsibility-segregation/src/test/resources/hibernate.cfg.xml similarity index 100% rename from cqrs/src/test/resources/hibernate.cfg.xml rename to command-query-responsibility-segregation/src/test/resources/hibernate.cfg.xml diff --git a/cqrs/src/test/resources/logback.xml b/command-query-responsibility-segregation/src/test/resources/logback.xml similarity index 100% rename from cqrs/src/test/resources/logback.xml rename to command-query-responsibility-segregation/src/test/resources/logback.xml diff --git a/commander/src/main/java/com/iluwatar/commander/RetryParams.java b/commander/src/main/java/com/iluwatar/commander/RetryParams.java index d6cf5dfec..ee3bf537f 100644 --- a/commander/src/main/java/com/iluwatar/commander/RetryParams.java +++ b/commander/src/main/java/com/iluwatar/commander/RetryParams.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.commander; /** diff --git a/commander/src/main/java/com/iluwatar/commander/TimeLimits.java b/commander/src/main/java/com/iluwatar/commander/TimeLimits.java index 6de079edd..bdb7caaf4 100644 --- a/commander/src/main/java/com/iluwatar/commander/TimeLimits.java +++ b/commander/src/main/java/com/iluwatar/commander/TimeLimits.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.commander; /** diff --git a/crtp/README.md b/curiously-recurring-template-pattern/README.md similarity index 97% rename from crtp/README.md rename to curiously-recurring-template-pattern/README.md index b767065ec..b1a382e56 100644 --- a/crtp/README.md +++ b/curiously-recurring-template-pattern/README.md @@ -1,180 +1,180 @@ ---- -title: Curiously Recurring Template Pattern -language: en -category: Structural -tag: - - Extensibility - - Idiom - - Instantiation ---- - -## Also known as - -* CRTP -* Mixin Inheritance -* Recursive Type Bound -* Recursive Generic -* Static Polymorphism - -## Intent - -Curiously Recurring Template Pattern (CRTP) is used to achieve a form of static polymorphism by having a class template derive from a template instantiation of its own class, allowing method overriding and polymorphic behavior at compile time rather than at runtime. - -## Explanation - -Real-world example - -> For a mixed martial arts promotion that is planning an event, ensuring that the fights are organized between athletes of the same weight class is crucial. This prevents mismatches between fighters of significantly different sizes, such as a heavyweight facing off against a bantamweight. - -In plain words - -> Make certain methods within a type to accept arguments specific to its subtypes. - -Wikipedia says - -> The curiously recurring template pattern (CRTP) is an idiom, originally in C++, in which a class X derives from a class template instantiation using X itself as a template argument. - -**Programmatic example** - -Let's define the generic interface Fighter. - -```java -public interface Fighter { - - void fight(T t); - -} -``` - -The MMAFighter class is used to instantiate fighters distinguished by their weight class. - -```java -public class MmaFighter> implements Fighter { - - private final String - name; - private final String - surname; - private final String - nickName; - private final String - speciality; - - public MmaFighter( - String name, - String surname, - String nickName, - String speciality) { - this.name = - name; - this.surname = - surname; - this.nickName = - nickName; - this.speciality = - speciality; - } - - @Override - public void fight( - T opponent) { - LOGGER.info( - "{} is going to fight against {}", - this, - opponent); - } - - @Override - public String toString() { - return - name + - " \"" + - nickName + - "\" " + - surname; - } -} -``` - -The followings are some subtypes of MmaFighter. - -```java -class MmaBantamweightFighter extends MmaFighter { - - public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} - -public class MmaHeavyweightFighter extends MmaFighter { - - public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} -``` - -A fighter is allowed to fight an opponent of the same weight classes. If the opponent is of a different weight class, an error is raised. - -```java -MmaBantamweightFighter fighter1=new MmaBantamweightFighter("Joe","Johnson","The Geek","Muay Thai"); - MmaBantamweightFighter fighter2=new MmaBantamweightFighter("Ed","Edwards","The Problem Solver","Judo"); - fighter1.fight(fighter2); // This is fine - - MmaHeavyweightFighter fighter3=new MmaHeavyweightFighter("Dave","Davidson","The Bug Smasher","Kickboxing"); - MmaHeavyweightFighter fighter4=new MmaHeavyweightFighter("Jack","Jackson","The Pragmatic","Brazilian Jiu-Jitsu"); - fighter3.fight(fighter4); // This is fine too - - fighter1.fight(fighter3); // This will raise a compilation error -``` - -## Class diagram - -![alt text](./etc/crtp.png "CRTP class diagram") - -## Applicability - -* When you need to extend the functionality of a class through inheritance but prefer compile-time polymorphism to runtime polymorphism for efficiency reasons. -* When you want to avoid the overhead of virtual functions but still achieve polymorphic behavior. -* In template metaprogramming to provide implementations of functions or policies that can be selected at compile time. -* You have type conflicts when chaining methods in an object hierarchy. -* You want to use a parameterized class method that can accept subclasses of the class as arguments, allowing it to be applied to objects that inherit from the class. -* You want certain methods to work only with instances of the same type, such as for achieving mutual comparability. - -## Tutorials - -* [The NuaH Blog](https://nuah.livejournal.com/328187.html) -* Yogesh Umesh Vaity's answer to [What does "Recursive type bound" in Generics mean?](https://stackoverflow.com/questions/7385949/what-does-recursive-type-bound-in-generics-mean) - -## Known uses - -* Implementing compile-time polymorphic interfaces in template libraries. -* Enhancing code reuse in libraries where performance is critical, like in mathematical computations, embedded systems, and real-time processing applications. -* [java.lang.Enum](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Enum.html) - -## Consequences - -Benefits: - -* Elimination of virtual function call overhead, enhancing performance. -* Safe reuse of the base class code without the risks associated with multiple inheritances. -* Greater flexibility and extensibility in compile-time polymorphism scenarios. - -Trade-offs: - -* Increased complexity in understanding and debugging due to the interplay of templates and inheritance. -* Can lead to code bloat because each instantiation of a template results in a new class. -* Less flexibility compared to runtime polymorphism as the behavior must be determined entirely at compile time. - -## Related Patterns - -* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): Can be used in conjunction with CRTP to instantiate derived classes without knowing their specific types. -* [Strategy](https://java-design-patterns.com/patterns/strategy/): CRTP can implement compile-time strategy selection. -* [Template Method](https://java-design-patterns.com/patterns/template-method/): Similar in structure but differs in that CRTP achieves behavior variation through compile-time polymorphism. - -## Credits - -* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb) -* [How do I decrypt "Enum>"?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106) +--- +title: Curiously Recurring Template Pattern +language: en +category: Structural +tag: + - Extensibility + - Idiom + - Instantiation +--- + +## Also known as + +* CRTP +* Mixin Inheritance +* Recursive Type Bound +* Recursive Generic +* Static Polymorphism + +## Intent + +Curiously Recurring Template Pattern (CRTP) is used to achieve a form of static polymorphism by having a class template derive from a template instantiation of its own class, allowing method overriding and polymorphic behavior at compile time rather than at runtime. + +## Explanation + +Real-world example + +> For a mixed martial arts promotion that is planning an event, ensuring that the fights are organized between athletes of the same weight class is crucial. This prevents mismatches between fighters of significantly different sizes, such as a heavyweight facing off against a bantamweight. + +In plain words + +> Make certain methods within a type to accept arguments specific to its subtypes. + +Wikipedia says + +> The curiously recurring template pattern (CRTP) is an idiom, originally in C++, in which a class X derives from a class template instantiation using X itself as a template argument. + +**Programmatic example** + +Let's define the generic interface Fighter. + +```java +public interface Fighter { + + void fight(T t); + +} +``` + +The MMAFighter class is used to instantiate fighters distinguished by their weight class. + +```java +public class MmaFighter> implements Fighter { + + private final String + name; + private final String + surname; + private final String + nickName; + private final String + speciality; + + public MmaFighter( + String name, + String surname, + String nickName, + String speciality) { + this.name = + name; + this.surname = + surname; + this.nickName = + nickName; + this.speciality = + speciality; + } + + @Override + public void fight( + T opponent) { + LOGGER.info( + "{} is going to fight against {}", + this, + opponent); + } + + @Override + public String toString() { + return + name + + " \"" + + nickName + + "\" " + + surname; + } +} +``` + +The followings are some subtypes of MmaFighter. + +```java +class MmaBantamweightFighter extends MmaFighter { + + public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} + +public class MmaHeavyweightFighter extends MmaFighter { + + public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} +``` + +A fighter is allowed to fight an opponent of the same weight classes. If the opponent is of a different weight class, an error is raised. + +```java +MmaBantamweightFighter fighter1=new MmaBantamweightFighter("Joe","Johnson","The Geek","Muay Thai"); + MmaBantamweightFighter fighter2=new MmaBantamweightFighter("Ed","Edwards","The Problem Solver","Judo"); + fighter1.fight(fighter2); // This is fine + + MmaHeavyweightFighter fighter3=new MmaHeavyweightFighter("Dave","Davidson","The Bug Smasher","Kickboxing"); + MmaHeavyweightFighter fighter4=new MmaHeavyweightFighter("Jack","Jackson","The Pragmatic","Brazilian Jiu-Jitsu"); + fighter3.fight(fighter4); // This is fine too + + fighter1.fight(fighter3); // This will raise a compilation error +``` + +## Class diagram + +![alt text](./etc/crtp.png "CRTP class diagram") + +## Applicability + +* When you need to extend the functionality of a class through inheritance but prefer compile-time polymorphism to runtime polymorphism for efficiency reasons. +* When you want to avoid the overhead of virtual functions but still achieve polymorphic behavior. +* In template metaprogramming to provide implementations of functions or policies that can be selected at compile time. +* You have type conflicts when chaining methods in an object hierarchy. +* You want to use a parameterized class method that can accept subclasses of the class as arguments, allowing it to be applied to objects that inherit from the class. +* You want certain methods to work only with instances of the same type, such as for achieving mutual comparability. + +## Tutorials + +* [The NuaH Blog](https://nuah.livejournal.com/328187.html) +* Yogesh Umesh Vaity's answer to [What does "Recursive type bound" in Generics mean?](https://stackoverflow.com/questions/7385949/what-does-recursive-type-bound-in-generics-mean) + +## Known uses + +* Implementing compile-time polymorphic interfaces in template libraries. +* Enhancing code reuse in libraries where performance is critical, like in mathematical computations, embedded systems, and real-time processing applications. +* [java.lang.Enum](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Enum.html) + +## Consequences + +Benefits: + +* Elimination of virtual function call overhead, enhancing performance. +* Safe reuse of the base class code without the risks associated with multiple inheritances. +* Greater flexibility and extensibility in compile-time polymorphism scenarios. + +Trade-offs: + +* Increased complexity in understanding and debugging due to the interplay of templates and inheritance. +* Can lead to code bloat because each instantiation of a template results in a new class. +* Less flexibility compared to runtime polymorphism as the behavior must be determined entirely at compile time. + +## Related Patterns + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): Can be used in conjunction with CRTP to instantiate derived classes without knowing their specific types. +* [Strategy](https://java-design-patterns.com/patterns/strategy/): CRTP can implement compile-time strategy selection. +* [Template Method](https://java-design-patterns.com/patterns/template-method/): Similar in structure but differs in that CRTP achieves behavior variation through compile-time polymorphism. + +## Credits + +* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb) +* [How do I decrypt "Enum>"?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106) diff --git a/crtp/etc/crtp.png b/curiously-recurring-template-pattern/etc/crtp.png similarity index 100% rename from crtp/etc/crtp.png rename to curiously-recurring-template-pattern/etc/crtp.png diff --git a/crtp/etc/crtp.urm.puml b/curiously-recurring-template-pattern/etc/crtp.urm.puml similarity index 100% rename from crtp/etc/crtp.urm.puml rename to curiously-recurring-template-pattern/etc/crtp.urm.puml diff --git a/curiously-recurring-template-pattern/etc/curiously-recurring-template-pattern.urm.puml b/curiously-recurring-template-pattern/etc/curiously-recurring-template-pattern.urm.puml new file mode 100644 index 000000000..02af47ddf --- /dev/null +++ b/curiously-recurring-template-pattern/etc/curiously-recurring-template-pattern.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/crtp/pom.xml b/curiously-recurring-template-pattern/pom.xml similarity index 96% rename from crtp/pom.xml rename to curiously-recurring-template-pattern/pom.xml index 1869f7b37..5f2227684 100644 --- a/crtp/pom.xml +++ b/curiously-recurring-template-pattern/pom.xml @@ -1,64 +1,64 @@ - - - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - crtp - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.crtp.App - - - - - - - - - + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + curiously-recurring-template-pattern + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.crtp.App + + + + + + + + + diff --git a/crtp/src/main/java/crtp/App.java b/curiously-recurring-template-pattern/src/main/java/crtp/App.java similarity index 100% rename from crtp/src/main/java/crtp/App.java rename to curiously-recurring-template-pattern/src/main/java/crtp/App.java diff --git a/crtp/src/main/java/crtp/Fighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/Fighter.java similarity index 97% rename from crtp/src/main/java/crtp/Fighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/Fighter.java index 675a3d975..40a7367ce 100644 --- a/crtp/src/main/java/crtp/Fighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/Fighter.java @@ -1,36 +1,36 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package crtp; - -/** - * Fighter interface. - * - * @param The type of fighter. - */ -public interface Fighter { - - void fight(T t); - -} +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package crtp; + +/** + * Fighter interface. + * + * @param The type of fighter. + */ +public interface Fighter { + + void fight(T t); + +} diff --git a/crtp/src/main/java/crtp/MmaBantamweightFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaBantamweightFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaBantamweightFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaBantamweightFighter.java index 737dcac92..25258c8bc 100644 --- a/crtp/src/main/java/crtp/MmaBantamweightFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaBantamweightFighter.java @@ -1,36 +1,36 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package crtp; - -/** - * MmaBantamweightFighter class. - */ -class MmaBantamweightFighter extends MmaFighter { - - public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package crtp; + +/** + * MmaBantamweightFighter class. + */ +class MmaBantamweightFighter extends MmaFighter { + + public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + } \ No newline at end of file diff --git a/crtp/src/main/java/crtp/MmaFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaFighter.java index 98f37a673..fd1155a5b 100644 --- a/crtp/src/main/java/crtp/MmaFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaFighter.java @@ -1,49 +1,49 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package crtp; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -/** - * MmaFighter class. - * - * @param MmaFighter derived class that uses itself as type parameter. - */ -@Slf4j -@Data -public class MmaFighter> implements Fighter { - - private final String name; - private final String surname; - private final String nickName; - private final String speciality; - - @Override - public void fight(T opponent) { - LOGGER.info("{} is going to fight against {}", this, opponent); - } - -} +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package crtp; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * MmaFighter class. + * + * @param MmaFighter derived class that uses itself as type parameter. + */ +@Slf4j +@Data +public class MmaFighter> implements Fighter { + + private final String name; + private final String surname; + private final String nickName; + private final String speciality; + + @Override + public void fight(T opponent) { + LOGGER.info("{} is going to fight against {}", this, opponent); + } + +} diff --git a/crtp/src/main/java/crtp/MmaHeavyweightFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaHeavyweightFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaHeavyweightFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaHeavyweightFighter.java index 4df63ef14..74c1f9147 100644 --- a/crtp/src/main/java/crtp/MmaHeavyweightFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaHeavyweightFighter.java @@ -1,36 +1,36 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package crtp; - -/** - * MmaHeavyweightFighter. - */ -public class MmaHeavyweightFighter extends MmaFighter { - - public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package crtp; + +/** + * MmaHeavyweightFighter. + */ +public class MmaHeavyweightFighter extends MmaFighter { + + public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} diff --git a/crtp/src/main/java/crtp/MmaLightweightFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaLightweightFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaLightweightFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaLightweightFighter.java index c9afd5481..4a3d606a8 100644 --- a/crtp/src/main/java/crtp/MmaLightweightFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaLightweightFighter.java @@ -1,36 +1,36 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package crtp; - -/** - * MmaLightweightFighter class. - */ -class MmaLightweightFighter extends MmaFighter { - - public MmaLightweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package crtp; + +/** + * MmaLightweightFighter class. + */ +class MmaLightweightFighter extends MmaFighter { + + public MmaLightweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} diff --git a/crtp/src/test/java/crtp/AppTest.java b/curiously-recurring-template-pattern/src/test/java/crtp/AppTest.java similarity index 100% rename from crtp/src/test/java/crtp/AppTest.java rename to curiously-recurring-template-pattern/src/test/java/crtp/AppTest.java diff --git a/crtp/src/test/java/crtp/FightTest.java b/curiously-recurring-template-pattern/src/test/java/crtp/FightTest.java similarity index 97% rename from crtp/src/test/java/crtp/FightTest.java rename to curiously-recurring-template-pattern/src/test/java/crtp/FightTest.java index 9c6a2ee61..279730d48 100644 --- a/crtp/src/test/java/crtp/FightTest.java +++ b/curiously-recurring-template-pattern/src/test/java/crtp/FightTest.java @@ -1,74 +1,74 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package crtp; - -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Slf4j -public class FightTest { - - /** - * A fighter has signed a contract with a promotion, and he will face some other fighters. A list of opponents is ready - * but for some reason not all of them belong to the same weight class. Let's ensure that the fighter will only face - * opponents in the same weight class. - */ - @Test - void testFighterCanFightOnlyAgainstSameWeightOpponents() { - MmaBantamweightFighter fighter = new MmaBantamweightFighter("Joe", "Johnson", "The Geek", "Muay Thai"); - List> opponents = getOpponents(); - List> challenged = new ArrayList<>(); - - opponents.forEach(challenger -> { - try { - ((MmaBantamweightFighter) challenger).fight(fighter); - challenged.add(challenger); - } catch (ClassCastException e) { - LOGGER.error(e.getMessage()); - } - }); - - assertFalse(challenged.isEmpty()); - assertTrue(challenged.stream().allMatch(c -> c instanceof MmaBantamweightFighter)); - } - - private static List> getOpponents() { - return List.of( - new MmaBantamweightFighter("Ed", "Edwards", "The Problem Solver", "Judo"), - new MmaLightweightFighter("Evan", "Evans", "Clean Coder", "Sambo"), - new MmaHeavyweightFighter("Dave", "Davidson", "The Bug Smasher", "Kickboxing"), - new MmaBantamweightFighter("Ray", "Raymond", "Scrum Master", "Karate"), - new MmaHeavyweightFighter("Jack", "Jackson", "The Pragmatic", "Brazilian Jiu-Jitsu") - ); - } - - -} +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package crtp; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Slf4j +public class FightTest { + + /** + * A fighter has signed a contract with a promotion, and he will face some other fighters. A list of opponents is ready + * but for some reason not all of them belong to the same weight class. Let's ensure that the fighter will only face + * opponents in the same weight class. + */ + @Test + void testFighterCanFightOnlyAgainstSameWeightOpponents() { + MmaBantamweightFighter fighter = new MmaBantamweightFighter("Joe", "Johnson", "The Geek", "Muay Thai"); + List> opponents = getOpponents(); + List> challenged = new ArrayList<>(); + + opponents.forEach(challenger -> { + try { + ((MmaBantamweightFighter) challenger).fight(fighter); + challenged.add(challenger); + } catch (ClassCastException e) { + LOGGER.error(e.getMessage()); + } + }); + + assertFalse(challenged.isEmpty()); + assertTrue(challenged.stream().allMatch(c -> c instanceof MmaBantamweightFighter)); + } + + private static List> getOpponents() { + return List.of( + new MmaBantamweightFighter("Ed", "Edwards", "The Problem Solver", "Judo"), + new MmaLightweightFighter("Evan", "Evans", "Clean Coder", "Sambo"), + new MmaHeavyweightFighter("Dave", "Davidson", "The Bug Smasher", "Kickboxing"), + new MmaBantamweightFighter("Ray", "Raymond", "Scrum Master", "Karate"), + new MmaHeavyweightFighter("Jack", "Jackson", "The Pragmatic", "Brazilian Jiu-Jitsu") + ); + } + + +} diff --git a/dao/README.md b/data-access-object/README.md similarity index 100% rename from dao/README.md rename to data-access-object/README.md diff --git a/dao/etc/dao.png b/data-access-object/etc/dao.png similarity index 100% rename from dao/etc/dao.png rename to data-access-object/etc/dao.png diff --git a/dao/etc/dao.ucls b/data-access-object/etc/dao.ucls similarity index 100% rename from dao/etc/dao.ucls rename to data-access-object/etc/dao.ucls diff --git a/dao/etc/dao.urm.puml b/data-access-object/etc/dao.urm.puml similarity index 100% rename from dao/etc/dao.urm.puml rename to data-access-object/etc/dao.urm.puml diff --git a/data-access-object/etc/data-access-object.urm.puml b/data-access-object/etc/data-access-object.urm.puml new file mode 100644 index 000000000..5c6e5f703 --- /dev/null +++ b/data-access-object/etc/data-access-object.urm.puml @@ -0,0 +1,69 @@ +@startuml +package com.iluwatar.dao { + class App { + - ALL_CUSTOMERS : String {static} + - DB_URL : String {static} + - LOGGER : Logger {static} + + App() + - addCustomers(customerDao : CustomerDao) {static} + - createDataSource() : DataSource {static} + - createSchema(dataSource : DataSource) {static} + - deleteSchema(dataSource : DataSource) {static} + + generateSampleCustomers() : List {static} + + main(args : String[]) {static} + - performOperationsUsing(customerDao : CustomerDao) {static} + } + class Customer { + - firstName : String + - id : int + - lastName : String + + Customer(id : int, firstName : String, lastName : String) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getFirstName() : String + + getId() : int + + getLastName() : String + + hashCode() : int + + setFirstName(firstName : String) + + setId(id : int) + + setLastName(lastName : String) + + toString() : String + } + interface CustomerDao { + + add(Customer) : boolean {abstract} + + delete(Customer) : boolean {abstract} + + getAll() : Stream {abstract} + + getById(int) : Optional {abstract} + + update(Customer) : boolean {abstract} + } + class CustomerSchemaSql { + + CREATE_SCHEMA_SQL : String {static} + + DELETE_SCHEMA_SQL : String {static} + - CustomerSchemaSql() + } + class DbCustomerDao { + - LOGGER : Logger {static} + - dataSource : DataSource + + DbCustomerDao(dataSource : DataSource) + + add(customer : Customer) : boolean + - createCustomer(resultSet : ResultSet) : Customer + + delete(customer : Customer) : boolean + + getAll() : Stream + + getById(id : int) : Optional + - getConnection() : Connection + - mutedClose(connection : Connection, statement : PreparedStatement, resultSet : ResultSet) + + update(customer : Customer) : boolean + } + class InMemoryCustomerDao { + - idToCustomer : Map + + InMemoryCustomerDao() + + add(customer : Customer) : boolean + + delete(customer : Customer) : boolean + + getAll() : Stream + + getById(id : int) : Optional + + update(customer : Customer) : boolean + } +} +DbCustomerDao ..|> CustomerDao +InMemoryCustomerDao ..|> CustomerDao +@enduml \ No newline at end of file diff --git a/dao/pom.xml b/data-access-object/pom.xml similarity index 98% rename from dao/pom.xml rename to data-access-object/pom.xml index 1d75f1f83..9685cbb96 100644 --- a/dao/pom.xml +++ b/data-access-object/pom.xml @@ -32,7 +32,7 @@ java-design-patterns 1.26.0-SNAPSHOT - dao + data-access-object org.junit.jupiter diff --git a/dao/src/main/java/com/iluwatar/dao/App.java b/data-access-object/src/main/java/com/iluwatar/dao/App.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/App.java rename to data-access-object/src/main/java/com/iluwatar/dao/App.java diff --git a/dao/src/main/java/com/iluwatar/dao/CustomException.java b/data-access-object/src/main/java/com/iluwatar/dao/CustomException.java similarity index 97% rename from dao/src/main/java/com/iluwatar/dao/CustomException.java rename to data-access-object/src/main/java/com/iluwatar/dao/CustomException.java index ce8ca5642..de907a641 100644 --- a/dao/src/main/java/com/iluwatar/dao/CustomException.java +++ b/data-access-object/src/main/java/com/iluwatar/dao/CustomException.java @@ -1,40 +1,40 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.dao; - -import java.io.Serial; - -/** - * Custom exception. - */ -public class CustomException extends Exception { - - @Serial - private static final long serialVersionUID = 1L; - - public CustomException(String message, Throwable cause) { - super(message, cause); - } -} +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.dao; + +import java.io.Serial; + +/** + * Custom exception. + */ +public class CustomException extends Exception { + + @Serial + private static final long serialVersionUID = 1L; + + public CustomException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/dao/src/main/java/com/iluwatar/dao/Customer.java b/data-access-object/src/main/java/com/iluwatar/dao/Customer.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/Customer.java rename to data-access-object/src/main/java/com/iluwatar/dao/Customer.java diff --git a/dao/src/main/java/com/iluwatar/dao/CustomerDao.java b/data-access-object/src/main/java/com/iluwatar/dao/CustomerDao.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/CustomerDao.java rename to data-access-object/src/main/java/com/iluwatar/dao/CustomerDao.java diff --git a/dao/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java b/data-access-object/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java rename to data-access-object/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java diff --git a/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java b/data-access-object/src/main/java/com/iluwatar/dao/DbCustomerDao.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java rename to data-access-object/src/main/java/com/iluwatar/dao/DbCustomerDao.java diff --git a/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java b/data-access-object/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java rename to data-access-object/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java diff --git a/dao/src/test/java/com/iluwatar/dao/AppTest.java b/data-access-object/src/test/java/com/iluwatar/dao/AppTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/AppTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/AppTest.java diff --git a/dao/src/test/java/com/iluwatar/dao/CustomerTest.java b/data-access-object/src/test/java/com/iluwatar/dao/CustomerTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/CustomerTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/CustomerTest.java diff --git a/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java b/data-access-object/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java diff --git a/dao/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java b/data-access-object/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java diff --git a/master-worker/etc/master-worker.urm.puml b/master-worker/etc/master-worker.urm.puml new file mode 100644 index 000000000..d5fc9e5d0 --- /dev/null +++ b/master-worker/etc/master-worker.urm.puml @@ -0,0 +1,78 @@ +@startuml +package com.iluwatar.masterworker.system.systemmaster { + class ArrayTransposeMaster { + + ArrayTransposeMaster(numOfWorkers : int) + ~ aggregateData() : ArrayResult + ~ setWorkers(num : int) : ArrayList + } + abstract class Master { + - allResultData : Hashtable> + - expectedNumResults : int + - finalResult : Result + - numOfWorkers : int + - workers : List + ~ Master(numOfWorkers : int) + ~ aggregateData() : Result {abstract} + - collectResult(data : Result, workerId : int) + - divideWork(input : Input) + + doWork(input : Input) + ~ getAllResultData() : Hashtable> + ~ getExpectedNumResults() : int + + getFinalResult() : Result + ~ getWorkers() : List + + receiveData(data : Result, w : Worker) + ~ setWorkers(int) : List {abstract} + } +} +package com.iluwatar.masterworker.system { + class ArrayTransposeMasterWorker { + + ArrayTransposeMasterWorker() + ~ setMaster(numOfWorkers : int) : Master + } + abstract class MasterWorker { + - master : Master + + MasterWorker(numOfWorkers : int) + + getResult(input : Input) : Result + ~ setMaster(int) : Master {abstract} + } +} +package com.iluwatar.masterworker { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class ArrayInput { + + ArrayInput(data : int[][]) + + divideData(num : int) : List> + ~ makeDivisions(data : int[][], num : int) : int[] {static} + } + class ArrayResult { + + ArrayResult(data : int[][]) + } + class ArrayUtilityMethods { + - LOGGER : Logger {static} + - RANDOM : SecureRandom {static} + + ArrayUtilityMethods() + + arraysSame(a1 : int[], a2 : int[]) : boolean {static} + + createRandomIntMatrix(rows : int, columns : int) : int[][] {static} + + matricesSame(m1 : int[][], m2 : int[][]) : boolean {static} + + printMatrix(matrix : int[][]) {static} + } + abstract class Input { + + data : T + + Input(data : T) + + divideData(int) : List> {abstract} + } + abstract class Result { + + data : T + + Result(data : T) + } +} +Master --> "-finalResult" Result +MasterWorker --> "-master" Master +ArrayInput --|> Input +ArrayResult --|> Result +ArrayTransposeMasterWorker --|> MasterWorker +ArrayTransposeMaster --|> Master +@enduml \ No newline at end of file diff --git a/module/.gitignore b/module/.gitignore deleted file mode 100644 index ecfa5dd46..000000000 --- a/module/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -error.txt -output.txt diff --git a/module/README.md b/module/README.md deleted file mode 100644 index feb1533ee..000000000 --- a/module/README.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Module -category: Structural -language: en -tag: - - Decoupling - - Encapsulation - - Layered architecture - - Object composition ---- - -## Intent - -The Module pattern aims to encapsulate a group of related elements, such as classes, functions, and variables, into a single unit or module, enhancing cohesion and reducing dependencies between different parts of an application. - -## Explanation - -Real-world example - -> Consider the organization of a modern kitchen as a real-world analogy to the Module pattern. In a kitchen, different sections are dedicated to specific functions: there's a cooking module with stoves and ovens, a cleaning module with sinks and dishwashers, and a storage module with refrigerators and cabinets. Each module encapsulates all the tools and equipment needed for its specific function, ensuring they are not intermingled with those of other modules. This organization enhances efficiency, as each section has everything necessary for its tasks, and reduces confusion by keeping unrelated items separate. This modular approach mirrors the Module pattern in software, where different functionalities are grouped into distinct, self-contained units that manage their own resources and dependencies. - -In plain words - -> The Module pattern encapsulates related functions and data into a single unit, allowing for organized and manageable software components. - -Wikipedia says - -> In software engineering, the module pattern is a design pattern used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept. -> -> This pattern can be implemented in several ways depending on the host programming language, such as the singleton design pattern, object-oriented static members in a class and procedural global functions. In Python, the pattern is built into the language, and each .py file is automatically a module. The same applies to Ada, where the package can be considered a module (similar to a static class). - -**Programmatic Example** - -The Module design pattern is a design pattern that provides a way to wrap a set of related functionalities into a single unit, which can be an object or a function. This pattern is particularly useful in large systems where it's necessary to group related functionality and data to improve code organization and readability. - -In the provided code, we have a great example of the Module pattern. The pattern is implemented using two modules: `FileLoggerModule` and `ConsoleLoggerModule`. Both of these modules are singletons, meaning that only one instance of each module can exist at a time. - -Here's a simplified version of the `FileLoggerModule`: - -```java -class FileLoggerModule extends Logger { - private static final String OUTPUT_FILE = "output.log"; - private static final String ERROR_FILE = "error.log"; - - private static FileLoggerModule instance; - - private FileLoggerModule() { - this.output = OUTPUT_FILE; - this.error = ERROR_FILE; - } - - public static FileLoggerModule getSingleton() { - if (instance == null) { - instance = new FileLoggerModule(); - } - return instance; - } - - @Override - public void printString(String message) { - System.out.println("Writing to " + output + ": " + message); - } - - @Override - public void printErrorString(String errorMessage) { - System.out.println("Writing to " + error + ": " + errorMessage); - } -} -``` - -In this module, we have a `getSingleton` method that ensures only one instance of `FileLoggerModule` is created. The `printString` and `printErrorString` methods are used to print messages and errors to the console, simulating writing to a file. - -Similarly, the `ConsoleLoggerModule` is another module that logs messages and errors to the console: - -```java -class ConsoleLoggerModule extends Logger { - private static ConsoleLoggerModule instance; - - private ConsoleLoggerModule() {} - - public static ConsoleLoggerModule getSingleton() { - if (instance == null) { - instance = new ConsoleLoggerModule(); - } - return instance; - } - - @Override - public void printString(String message) { - System.out.println("Console Output: " + message); - } - - @Override - public void printErrorString(String errorMessage) { - System.err.println("Console Error: " + errorMessage); - } -} -``` - -In the `App` class, these modules are used to log messages: - -```java -public class App { - public void prepare() { - FileLoggerModule.getSingleton().prepare(); - ConsoleLoggerModule.getSingleton().prepare(); - } - - public void execute(String message) { - FileLoggerModule.getSingleton().printString(message); - ConsoleLoggerModule.getSingleton().printString(message); - } - - public static void main(String[] args) { - App app = new App(); - app.prepare(); - app.execute("Hello, Module Pattern!"); - app.unprepare(); - } -} -``` - -In the `prepare` method, the `prepare` method of each module is called. In the `execute` method, the `printString` method of each module is used to log a message. This demonstrates how the Module pattern can be used to encapsulate related functionality into a single unit, improving code organization and readability. - -## Class diagram - -![Module](./etc/module.png "Module") - -## Applicability - -* When you need to group related functionality and data to improve code organization and readability. -* To encapsulate internal details of a part of a program, exposing only what is necessary through a well-defined interface. -* Useful in large systems for dividing the codebase into manageable sections. - -## Known Uses - -* Java Platform Module System introduced in Java 9. -* Organizing libraries or frameworks into coherent units. -* Web applications that segment logic into various modules for maintainability. - -## Consequences - -Benefits: - -* Enhances code clarity and maintainability by grouping related features. -* Reduces global scope pollution and namespace clashes. -* Facilitates better testing and debugging by isolating functionalities. - -Trade-offs: - -* Initial complexity in setting up modules and their interactions. -* Over-modularization can lead to unnecessary complexity and overhead. - -## Related Patterns - -* [Facade](https://java-design-patterns.com/patterns/facade/): Simplifies the module's interface for clients. Both aim to simplify usage by hiding complexity. -* [Singleton](https://java-design-patterns.com/patterns/singleton/): Often used within a module to ensure a single instance of a component is used across the system. - -## Credits - -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) -* [Effective Java](https://amzn.to/4cGk2Jz) -* [Java 9 Modularity: Patterns and Practices for Developing Maintainable Applications](https://amzn.to/4b4CWIK) diff --git a/module/etc/module.png b/module/etc/module.png deleted file mode 100644 index a26807d290c0d2aced42c5e5d48cf0780e9c4d2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18027 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�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 b&*xx@wCm+^Q{eyCf+Z;`E0Qa$`}Y3>Bi8;O diff --git a/module/etc/module.ucls b/module/etc/module.ucls deleted file mode 100644 index d2519b856..000000000 --- a/module/etc/module.ucls +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/module/etc/module.urm.puml b/module/etc/module.urm.puml deleted file mode 100644 index b92446ca1..000000000 --- a/module/etc/module.urm.puml +++ /dev/null @@ -1,43 +0,0 @@ -@startuml -package com.iluwatar.module { - class App { - + consoleLoggerModule : ConsoleLoggerModule {static} - + fileLoggerModule : FileLoggerModule {static} - + App() - + execute(args : String[]) {static} - + main(args : String[]) {static} - + prepare() {static} - + unprepare() {static} - } - class ConsoleLoggerModule { - - LOGGER : Logger {static} - + error : PrintStream - + output : PrintStream - - singleton : ConsoleLoggerModule {static} - - ConsoleLoggerModule() - + getSingleton() : ConsoleLoggerModule {static} - + prepare() : ConsoleLoggerModule - + printErrorString(value : String) - + printString(value : String) - + unprepare() - } - class FileLoggerModule { - - ERROR_FILE : String {static} - - LOGGER : Logger {static} - - OUTPUT_FILE : String {static} - + error : PrintStream - + output : PrintStream - - singleton : FileLoggerModule {static} - - FileLoggerModule() - + getSingleton() : FileLoggerModule {static} - + prepare() : FileLoggerModule - + printErrorString(value : String) - + printString(value : String) - + unprepare() - } -} -FileLoggerModule --> "-singleton" FileLoggerModule -App --> "-consoleLoggerModule" ConsoleLoggerModule -ConsoleLoggerModule --> "-singleton" ConsoleLoggerModule -App --> "-fileLoggerModule" FileLoggerModule -@enduml \ No newline at end of file diff --git a/module/pom.xml b/module/pom.xml deleted file mode 100644 index 4f6c0dcb8..000000000 --- a/module/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - module - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.module.App - - - - - - - - - diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java deleted file mode 100644 index c0e03608b..000000000 --- a/module/src/main/java/com/iluwatar/module/App.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.module; - -import java.io.FileNotFoundException; - -/** - * The Module pattern can be considered a Creational pattern and a Structural pattern. It manages - * the creation and organization of other elements, and groups them as the structural pattern does. - * An object that applies this pattern can provide the equivalent of a namespace, providing the - * initialization and finalization process of a static class or a class with static members with - * cleaner, more concise syntax and semantics. - * - *

The below example demonstrates a use case for testing two different modules: File Logger and - * Console Logger - */ -public class App { - - private static final String ERROR = "Error"; - private static final String MESSAGE = "Message"; - public static FileLoggerModule fileLoggerModule; - public static ConsoleLoggerModule consoleLoggerModule; - - /** - * Following method performs the initialization. - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - public static void prepare() throws FileNotFoundException { - - /* Create new singleton objects and prepare their modules */ - fileLoggerModule = FileLoggerModule.getSingleton().prepare(); - consoleLoggerModule = ConsoleLoggerModule.getSingleton().prepare(); - } - - /** - * Following method performs the finalization. - */ - public static void unprepare() { - - /* Close all resources */ - fileLoggerModule.unprepare(); - consoleLoggerModule.unprepare(); - } - - /** - * Following method is main executor. - */ - public static void execute() { - - /* Send logs on file system */ - fileLoggerModule.printString(MESSAGE); - fileLoggerModule.printErrorString(ERROR); - - /* Send logs on console */ - consoleLoggerModule.printString(MESSAGE); - consoleLoggerModule.printErrorString(ERROR); - } - - /** - * Program entry point. - * - * @param args command line args. - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - public static void main(final String... args) throws FileNotFoundException { - prepare(); - execute(); - unprepare(); - } -} diff --git a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java deleted file mode 100644 index c29e57c0e..000000000 --- a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.module; - -import java.io.PrintStream; -import lombok.extern.slf4j.Slf4j; - -/** - * The ConsoleLoggerModule is responsible for showing logs on System Console. - * - *

The below example demonstrates a Console logger module, which can print simple and error - * messages in two designated formats - */ -@Slf4j -public final class ConsoleLoggerModule { - - private static ConsoleLoggerModule singleton = null; - - public PrintStream output = null; - public PrintStream error = null; - - private ConsoleLoggerModule() { - } - - /** - * Static method to get single instance of class. - * - * @return singleton instance of ConsoleLoggerModule - */ - public static ConsoleLoggerModule getSingleton() { - - if (ConsoleLoggerModule.singleton == null) { - ConsoleLoggerModule.singleton = new ConsoleLoggerModule(); - } - - return ConsoleLoggerModule.singleton; - } - - /** - * Following method performs the initialization. - */ - public ConsoleLoggerModule prepare() { - - LOGGER.debug("ConsoleLoggerModule::prepare();"); - - this.output = new PrintStream(System.out); - this.error = new PrintStream(System.err); - - return this; - } - - /** - * Following method performs the finalization. - */ - public void unprepare() { - - if (this.output != null) { - - this.output.flush(); - this.output.close(); - } - - if (this.error != null) { - - this.error.flush(); - this.error.close(); - } - - LOGGER.debug("ConsoleLoggerModule::unprepare();"); - } - - /** - * Used to print a message. - * - * @param value will be printed on console - */ - public void printString(final String value) { - this.output.println(value); - } - - /** - * Used to print a error message. - * - * @param value will be printed on error console - */ - public void printErrorString(final String value) { - this.error.println(value); - } -} diff --git a/module/src/main/java/com/iluwatar/module/FileLoggerModule.java b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java deleted file mode 100644 index 7a226b643..000000000 --- a/module/src/main/java/com/iluwatar/module/FileLoggerModule.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.module; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; -import lombok.extern.slf4j.Slf4j; - -/** - * The FileLoggerModule is responsible for showing logs on File System. - * - *

The below example demonstrates a File logger module, which can print simple and error - * messages in two designated files - */ -@Slf4j -public final class FileLoggerModule { - - private static FileLoggerModule singleton = null; - - private static final String OUTPUT_FILE = "output.txt"; - private static final String ERROR_FILE = "error.txt"; - - public PrintStream output = null; - public PrintStream error = null; - - private FileLoggerModule() { - } - - /** - * Static method to get single instance of class. - * - * @return singleton instance of FileLoggerModule - */ - public static FileLoggerModule getSingleton() { - - if (FileLoggerModule.singleton == null) { - FileLoggerModule.singleton = new FileLoggerModule(); - } - - return FileLoggerModule.singleton; - } - - /** - * Following method performs the initialization. - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - public FileLoggerModule prepare() throws FileNotFoundException { - - LOGGER.debug("FileLoggerModule::prepare();"); - - this.output = new PrintStream(new FileOutputStream(OUTPUT_FILE)); - this.error = new PrintStream(new FileOutputStream(ERROR_FILE)); - - return this; - } - - /** - * Following method performs the finalization. - */ - public void unprepare() { - - if (this.output != null) { - - this.output.flush(); - this.output.close(); - } - - if (this.error != null) { - - this.error.flush(); - this.error.close(); - } - - LOGGER.debug("FileLoggerModule::unprepare();"); - } - - /** - * Used to print a message. - * - * @param value will be printed in file - */ - public void printString(final String value) { - this.output.println(value); - } - - /** - * Used to print a error message. - * - * @param value will be printed on error file - */ - public void printErrorString(final String value) { - this.error.println(value); - } -} diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java deleted file mode 100644 index c385b8d8a..000000000 --- a/module/src/test/java/com/iluwatar/module/AppTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.module; - -import java.io.FileNotFoundException; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - -/** - * Tests that Module example runs without errors. - */ -final class AppTest { - - @Test - void shouldExecuteWithoutException() { - assertDoesNotThrow((Executable) App::main); - } -} diff --git a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java deleted file mode 100644 index 6d05566b4..000000000 --- a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.module; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; - -/** - * The Module pattern can be considered a Creational pattern and a Structural pattern. It manages - * the creation and organization of other elements, and groups them as the structural pattern does. - * An object that applies this pattern can provide the equivalent of a namespace, providing the - * initialization and finalization process of a static class or a class with static members with - * cleaner, more concise syntax and semantics. - *

- * The below example demonstrates a JUnit test for testing two different modules: File Logger and - * Console Logger - */ -@Slf4j -public final class FileLoggerModuleTest { - - private static final String OUTPUT_FILE = "output.txt"; - private static final String ERROR_FILE = "error.txt"; - - private static final String MESSAGE = "MESSAGE"; - private static final String ERROR = "ERROR"; - - - /** - * This test verify that 'MESSAGE' is perfectly printed in output file - * - * @throws IOException if program is not able to find log files (output.txt and error.txt) - */ - @Test - void testFileMessage() throws IOException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Print 'Message' in file */ - fileLoggerModule.printString(MESSAGE); - - /* Test if 'Message' is printed in file */ - assertEquals(readFirstLine(OUTPUT_FILE), MESSAGE); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that nothing is printed in output file - * - * @throws IOException if program is not able to find log files (output.txt and error.txt) - */ - @Test - void testNoFileMessage() throws IOException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Test if nothing is printed in file */ - assertNull(readFirstLine(OUTPUT_FILE)); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that 'ERROR' is perfectly printed in error file - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - @Test - void testFileErrorMessage() throws FileNotFoundException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Print 'Error' in file */ - fileLoggerModule.printErrorString(ERROR); - - /* Test if 'Message' is printed in file */ - assertEquals(ERROR, readFirstLine(ERROR_FILE)); - - /* Un-prepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that nothing is printed in error file - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - @Test - void testNoFileErrorMessage() throws FileNotFoundException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Test if nothing is printed in file */ - assertNull(readFirstLine(ERROR_FILE)); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * Utility method to read first line of a file - * - * @param file as file name to be read - * @return a string value as first line in file - */ - private static String readFirstLine(final String file) { - - String firstLine = null; - try (var bufferedReader = new BufferedReader(new FileReader(file))) { - - while (bufferedReader.ready()) { - - /* Read the line */ - firstLine = bufferedReader.readLine(); - } - - LOGGER.info("ModuleTest::readFirstLine() : firstLine : " + firstLine); - - } catch (final IOException e) { - LOGGER.error("ModuleTest::readFirstLine()", e); - } - - return firstLine; - } -} diff --git a/pom.xml b/pom.xml index 6c8a03c18..a22f0ac9c 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ adapter bridge composite - dao + data-access-object data-mapper decorator facade @@ -99,7 +99,6 @@ producer-consumer pipeline poison-pill - reader-writer-lock lazy-loading service-layer specification @@ -131,7 +130,6 @@ factory-kit feature-toggle value-object - module monad mute-idiom hexagonal @@ -150,7 +148,7 @@ balking extension-objects marker - cqrs + command-query-responsibility-segregation event-sourcing data-transfer-object throttling @@ -164,7 +162,6 @@ collection-pipeline master-worker spatial-partition - priority-queue commander type-object bytecode @@ -210,7 +207,7 @@ context-object thread-local-storage optimistic-offline-lock - crtp + curiously-recurring-template-pattern log-aggregation anti-corruption-layer health-check diff --git a/priority-queue/README.md b/priority-queue/README.md deleted file mode 100644 index f034b96b2..000000000 --- a/priority-queue/README.md +++ /dev/null @@ -1,227 +0,0 @@ ---- -title: Priority Queue -category: Concurrency -language: en -tag: - - Performance - - Scalability - - Synchronization - - Thread management ---- - -## Also known as - -* Priority Heap -* Priority List - -## Intent - -The Priority Queue design pattern provides a way to manage a collection of elements where each element has a priority, and elements are accessed and removed based on their priority rather than their insertion order. - -## Explanation - -Real world example - -> Imagine an emergency room in a hospital. Patients arrive with varying degrees of urgency: some have minor injuries, while others have life-threatening conditions. The hospital uses a priority queue system to manage these patients. Instead of treating patients on a first-come, first-served basis, the medical staff assigns a priority level to each patient based on the severity of their condition. Patients with more critical conditions (higher priority) are treated before those with less severe issues, ensuring that urgent cases receive immediate attention. This system efficiently manages resources and prioritizes care, similar to how a priority queue handles elements based on their priority. - -In plain words - -> Priority Queue enables processing of high priority messages first, regardless of queue size or message age. - -Wikipedia says - -> In computer science, a priority queue is an abstract data type similar to regular queue or stack data structure in which each element additionally has a "priority" associated with it. In a priority queue, an element with high priority is served before an element with low priority. - -**Programmatic Example** - -Looking at a video processing example, let's first see the `Message` structure. - -```java -public class Message implements Comparable { - - private final String message; - private final int priority; // define message priority in queue - - public Message(String message, int priority) { - this.message = message; - this.priority = priority; - } - - @Override - public int compareTo(Message o) { - return priority - o.priority; - } - // ... -} -``` - -Here's `PriorityMessageQueue` that handles storing the messages and serving them in priority order. - -```java -public class PriorityMessageQueue { - - // ... - - public T remove() { - if (isEmpty()) { - return null; - } - - final var root = queue[0]; - queue[0] = queue[size - 1]; - size--; - maxHeapifyDown(); - return root; - } - - public void add(T t) { - ensureCapacity(); - queue[size] = t; - size++; - maxHeapifyUp(); - } - - // ... -} -``` - -`QueueManager` has a `PriorityMessageQueue` and makes it easy to `publishMessage` and `receiveMessage`. - -```java -public class QueueManager { - - private final PriorityMessageQueue messagePriorityMessageQueue; - - public QueueManager(int initialCapacity) { - messagePriorityMessageQueue = new PriorityMessageQueue<>(new Message[initialCapacity]); - } - - public void publishMessage(Message message) { - messagePriorityMessageQueue.add(message); - } - - public Message receiveMessage() { - if (messagePriorityMessageQueue.isEmpty()) { - return null; - } - return messagePriorityMessageQueue.remove(); - } -} -``` - -`Worker` constantly polls `QueueManager` for highest priority message and processes it. - -```java - -@Slf4j -public class Worker { - - private final QueueManager queueManager; - - public Worker(QueueManager queueManager) { - this.queueManager = queueManager; - } - - public void run() throws Exception { - while (true) { - var message = queueManager.receiveMessage(); - if (message == null) { - LOGGER.info("No Message ... waiting"); - Thread.sleep(200); - } else { - processMessage(message); - } - } - } - - private void processMessage(Message message) { - LOGGER.info(message.toString()); - } -} -``` - -Here's the full example how we create an instance of `QueueManager` and process messages using `Worker`. - -```java -var queueManager = new QueueManager(100); - -for (var i = 0; i< 100; i++) { - queueManager.publishMessage(new Message("Low Message Priority", 0)); -} - -for(var i = 0; i< 100; i++) { - queueManager.publishMessage(new Message("High Message Priority", 1)); -} - -var worker = new Worker(queueManager); -worker.run(); -``` - -Program output: - -``` -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -No Message ... waiting -No Message ... waiting -No Message ... waiting -``` - -## Class diagram - -![alt text](./etc/priority-queue.urm.png "Priority Queue pattern class diagram") - -## Applicability - -Use the Priority Queue pattern when: - -* You need to manage tasks or elements that have different priorities. -* Applicable in scheduling systems where tasks need to be executed based on their priority. -* Useful in scenarios where you need to handle a large number of elements with varying importance levels efficiently. - -## Known Uses - -* Task scheduling in operating systems. -* Job scheduling in servers and batch processing systems. -* Event simulation systems where events are processed based on their scheduled time. -* Pathfinding algorithms (e.g., Dijkstra's or A* algorithms). - -## Consequences - -Benefits: - -* Efficient management of elements based on priority. -* Enhanced performance for priority-based access and removal operations. -* Improved scalability in systems requiring prioritized task execution. - -Trade-offs: - -* Increased complexity in implementation and maintenance compared to simple queues. -* Potential for higher memory usage due to the underlying data structures. -* Requires careful synchronization in a multi-threaded environment to avoid concurrency issues. - -## Related Patterns - -* Observer: Can be used alongside Priority Queue to notify when elements with high priority are processed. - -## Credits - -* [Priority Queue pattern - Microsoft](https://docs.microsoft.com/en-us/azure/architecture/patterns/priority-queue) diff --git a/priority-queue/etc/priority-queue.urm.png b/priority-queue/etc/priority-queue.urm.png deleted file mode 100644 index e0b4295a59863f1af83f929dba233d57cbc8932d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52777 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 Y#3~P^{?%O!em$U~sG*QAckjvn0gi5&!vFvP diff --git a/priority-queue/etc/priority-queue.urm.puml b/priority-queue/etc/priority-queue.urm.puml deleted file mode 100644 index cee118f57..000000000 --- a/priority-queue/etc/priority-queue.urm.puml +++ /dev/null @@ -1,54 +0,0 @@ -@startuml -package com.iluwatar.priority.queue { - class Application { - + Application() - + main(args : String[]) {static} - } - class Message { - - message : String - - priority : int - + Message(message : String, priority : int) - + compareTo(o : Message) : int - + toString() : String - } - class PriorityMessageQueue { - - LOGGER : Logger {static} - - capacity : int - - queue : T[] - - size : int - + PriorityMessageQueue(queue : T[]) - + add(t : T extends Comparable) - - ensureCapacity() - - hasLeftChild(index : int) : boolean - - hasParent(index : int) : boolean - - hasRightChild(index : int) : boolean - + isEmpty() : boolean - - left(parentIndex : int) : T extends Comparable - - leftChildIndex(parentPos : int) : int - - maxHeapifyDown() - - maxHeapifyUp() - - parent(childIndex : int) : T extends Comparable - - parentIndex(pos : int) : int - + print() - + remove() : T extends Comparable - - right(parentIndex : int) : T extends Comparable - - rightChildIndex(parentPos : int) : int - - swap(fpos : int, tpos : int) - } - class QueueManager { - - messagePriorityMessageQueue : PriorityMessageQueue - + QueueManager(initialCapacity : int) - + publishMessage(message : Message) - + receiveMessage() : Message - } - class Worker { - - LOGGER : Logger {static} - - queueManager : QueueManager - + Worker(queueManager : QueueManager) - - processMessage(message : Message) - + run() - } -} -QueueManager --> "-messagePriorityMessageQueue" PriorityMessageQueue -Worker --> "-queueManager" QueueManager -@enduml \ No newline at end of file diff --git a/priority-queue/pom.xml b/priority-queue/pom.xml deleted file mode 100644 index 63eed2c90..000000000 --- a/priority-queue/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - priority-queue - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.priority.queue.Application - - - - - - - - - diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java deleted file mode 100644 index 9d9935ade..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.priority.queue; - -/** - * Prioritize requests sent to services so that requests with a higher priority are received and - * processed more quickly than those of a lower priority. This pattern is useful in applications - * that offer different service level guarantees to individual clients. Example :Send multiple - * message with different priority to worker queue. Worker execute higher priority message first - * - * @see "https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589794(v=pandp.10)" - */ -public class Application { - /** - * main entry. - */ - public static void main(String[] args) throws Exception { - - var queueManager = new QueueManager(10); - - // push some message to queue - // Low Priority message - for (var i = 0; i < 10; i++) { - queueManager.publishMessage(new Message("Low Message Priority", 0)); - } - - // High Priority message - for (var i = 0; i < 10; i++) { - queueManager.publishMessage(new Message("High Message Priority", 1)); - } - - // run worker - var worker = new Worker(queueManager); - worker.run(); - - - } -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Message.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Message.java deleted file mode 100644 index 09bae85b3..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Message.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.priority.queue; - -/** - * Message bean. - */ -public class Message implements Comparable { - private final String message; - private final int priority; // define message priority in queue - - - public Message(String message, int priority) { - this.message = message; - this.priority = priority; - } - - @Override - public int compareTo(Message o) { - return priority - o.priority; - } - - @Override - public String toString() { - return "Message{" - + "message='" + message + '\'' - + ", priority=" + priority - + '}'; - } -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/PriorityMessageQueue.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/PriorityMessageQueue.java deleted file mode 100644 index 09704f15e..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/PriorityMessageQueue.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.priority.queue; - -import static java.util.Arrays.copyOf; - -import lombok.extern.slf4j.Slf4j; - -/** - * Keep high Priority message on top using maxHeap. - * - * @param : DataType to push in Queue - */ -@Slf4j -public class PriorityMessageQueue { - - private int size = 0; - - private int capacity; - - - private T[] queue; - - public PriorityMessageQueue(T[] queue) { - this.queue = queue; - this.capacity = queue.length; - } - - /** - * Remove top message from queue. - */ - public T remove() { - if (isEmpty()) { - return null; - } - - final var root = queue[0]; - queue[0] = queue[size - 1]; - size--; - maxHeapifyDown(); - return root; - } - - /** - * Add message to queue. - */ - public void add(T t) { - ensureCapacity(); - queue[size] = t; - size++; - maxHeapifyUp(); - } - - /** - * Check queue size. - */ - public boolean isEmpty() { - return size == 0; - } - - - private void maxHeapifyDown() { - var index = 0; - while (hasLeftChild(index)) { - - var smallerIndex = leftChildIndex(index); - - if (hasRightChild(index) && right(index).compareTo(left(index)) > 0) { - smallerIndex = rightChildIndex(index); - } - - if (queue[index].compareTo(queue[smallerIndex]) > 0) { - break; - } else { - swap(index, smallerIndex); - } - - index = smallerIndex; - - - } - - } - - private void maxHeapifyUp() { - var index = size - 1; - while (hasParent(index) && parent(index).compareTo(queue[index]) < 0) { - swap(parentIndex(index), index); - index = parentIndex(index); - } - } - - - // index - private int parentIndex(int pos) { - return (pos - 1) / 2; - } - - private int leftChildIndex(int parentPos) { - return 2 * parentPos + 1; - } - - private int rightChildIndex(int parentPos) { - return 2 * parentPos + 2; - } - - // value - private T parent(int childIndex) { - return queue[parentIndex(childIndex)]; - } - - private T left(int parentIndex) { - return queue[leftChildIndex(parentIndex)]; - } - - private T right(int parentIndex) { - return queue[rightChildIndex(parentIndex)]; - } - - // check - private boolean hasLeftChild(int index) { - return leftChildIndex(index) < size; - } - - private boolean hasRightChild(int index) { - return rightChildIndex(index) < size; - } - - private boolean hasParent(int index) { - return parentIndex(index) >= 0; - } - - private void swap(int fpos, int tpos) { - var tmp = queue[fpos]; - queue[fpos] = queue[tpos]; - queue[tpos] = tmp; - } - - private void ensureCapacity() { - if (size == capacity) { - capacity = capacity * 2; - queue = copyOf(queue, capacity); - } - } - - /** - * For debug .. print current state of queue - */ - public void print() { - for (var i = 0; i <= size / 2; i++) { - LOGGER.info(" PARENT : " + queue[i] + " LEFT CHILD : " - + left(i) + " RIGHT CHILD :" + right(i)); - } - } - -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java deleted file mode 100644 index 2d372c7a8..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.priority.queue; - -/** - * Manage priority queue. - */ -public class QueueManager { - /* - Priority message - */ - private final PriorityMessageQueue messagePriorityMessageQueue; - - public QueueManager(int initialCapacity) { - messagePriorityMessageQueue = new PriorityMessageQueue<>(new Message[initialCapacity]); - } - - /** - * Publish message to queue. - */ - public void publishMessage(Message message) { - messagePriorityMessageQueue.add(message); - } - - - /** - * Receive message from queue. - */ - public Message receiveMessage() { - if (messagePriorityMessageQueue.isEmpty()) { - return null; - } - return messagePriorityMessageQueue.remove(); - } - - -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Worker.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Worker.java deleted file mode 100644 index 8bd3ba1e1..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Worker.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.priority.queue; - -import lombok.extern.slf4j.Slf4j; - -/** - * Message Worker. - */ -@Slf4j -public class Worker { - - private final QueueManager queueManager; - - public Worker(QueueManager queueManager) { - this.queueManager = queueManager; - } - - /** - * Keep checking queue for message. - */ - @SuppressWarnings("squid:S2189") - public void run() throws Exception { - while (true) { - var message = queueManager.receiveMessage(); - if (message == null) { - LOGGER.info("No Message ... waiting"); - Thread.sleep(200); - } else { - processMessage(message); - } - } - } - - /** - * Process message. - */ - private void processMessage(Message message) { - LOGGER.info(message.toString()); - } - -} diff --git a/priority-queue/src/test/java/com/iluwatar/priority/queue/PriorityMessageQueueTest.java b/priority-queue/src/test/java/com/iluwatar/priority/queue/PriorityMessageQueueTest.java deleted file mode 100644 index d539e4e8a..000000000 --- a/priority-queue/src/test/java/com/iluwatar/priority/queue/PriorityMessageQueueTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.priority.queue; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - -/** - * Test case for order of messages - */ -class PriorityMessageQueueTest { - - - @Test - void remove() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new String[2]); - var pushMessage = "test"; - stringPriorityMessageQueue.add(pushMessage); - assertEquals(stringPriorityMessageQueue.remove(), pushMessage); - } - - @Test - void add() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new Integer[2]); - stringPriorityMessageQueue.add(1); - stringPriorityMessageQueue.add(5); - stringPriorityMessageQueue.add(10); - stringPriorityMessageQueue.add(3); - assertEquals(10, (int) stringPriorityMessageQueue.remove()); - } - - @Test - void isEmpty() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new Integer[2]); - assertTrue(stringPriorityMessageQueue.isEmpty()); - stringPriorityMessageQueue.add(1); - stringPriorityMessageQueue.remove(); - assertTrue(stringPriorityMessageQueue.isEmpty()); - } - - @Test - void testEnsureSize() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new Integer[2]); - assertTrue(stringPriorityMessageQueue.isEmpty()); - stringPriorityMessageQueue.add(1); - stringPriorityMessageQueue.add(2); - stringPriorityMessageQueue.add(2); - stringPriorityMessageQueue.add(3); - assertEquals(3, (int) stringPriorityMessageQueue.remove()); - } -} \ No newline at end of file diff --git a/priority-queue/src/test/java/com/iluwatar/priority/queue/QueueManagerTest.java b/priority-queue/src/test/java/com/iluwatar/priority/queue/QueueManagerTest.java deleted file mode 100644 index c5f2a515b..000000000 --- a/priority-queue/src/test/java/com/iluwatar/priority/queue/QueueManagerTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.priority.queue; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -/** - * Check queue manager - */ -class QueueManagerTest { - - @Test - void publishMessage() { - var queueManager = new QueueManager(2); - var testMessage = new Message("Test Message", 1); - queueManager.publishMessage(testMessage); - var recivedMessage = queueManager.receiveMessage(); - assertEquals(testMessage, recivedMessage); - } - - @Test - void receiveMessage() { - var queueManager = new QueueManager(2); - var testMessage1 = new Message("Test Message 1", 1); - queueManager.publishMessage(testMessage1); - var testMessage2 = new Message("Test Message 2", 2); - queueManager.publishMessage(testMessage2); - var recivedMessage = queueManager.receiveMessage(); - assertEquals(testMessage2, recivedMessage); - } -} \ No newline at end of file diff --git a/reader-writer-lock/README.md b/reader-writer-lock/README.md deleted file mode 100644 index 8bd7214da..000000000 --- a/reader-writer-lock/README.md +++ /dev/null @@ -1,192 +0,0 @@ ---- -title: Reader-Writer Lock -category: Concurrency -language: en -tag: - - Asynchronous - - Concurrency - - Performance - - Resource management - - Synchronization - - Thread management ---- - -## Also known as - -* Shared-Exclusive Lock - -## Intent - -Allow concurrent access to a shared resource for read operations while limiting access for write operations to ensure data consistency. - -## Explanation - -Real world example - -> Imagine a library where patrons frequently come to read books. The library allows multiple people to read the same book simultaneously without any issues. However, when someone wants to update or correct the content of the book, the library ensures that no one else is reading the book during the update process. This ensures that the book's content remains consistent and accurate, similar to how a Reader-Writer Lock allows multiple threads to read a shared resource concurrently while restricting write access to one thread at a time. - -In plain words - -> The Reader-Writer Lock design pattern allows concurrent read access to a shared resource while ensuring exclusive write access to maintain data consistency. - -Wikipedia says - -> In computer science, a readers–writer (single-writer lock, a multi-reader lock, a push lock, or an MRSW lock) is a synchronization primitive that solves one of the readers–writers problems. - -**Programmatic Example** - -The Reader-Writer Lock design pattern allows concurrent read access to a shared resource while ensuring exclusive write access to maintain data consistency. This pattern is particularly useful in scenarios where read operations are more frequent than write operations. - -First, we have the `Reader` class. This class represents a reader that can read a shared resource when it acquires the read lock. The `run` method locks the read lock, performs the read operation, and then unlocks the read lock. - -```java -@Slf4j -public class Reader implements Runnable { - - private Lock readLock; - private String name; - private long readingTime; - - public Reader(String name, Lock readLock, long readingTime) { - this.name = name; - this.readLock = readLock; - this.readingTime = readingTime; - } - - @Override - public void run() { - readLock.lock(); - try { - read(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when reading", e); - Thread.currentThread().interrupt(); - } finally { - readLock.unlock(); - } - } - - public void read() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(readingTime); - LOGGER.info("{} finish after reading {}ms", name, readingTime); - } -} -``` - -Next, we have the `Writer` class. This class represents a writer that can write to a shared resource when it acquires the write lock. Similar to the `Reader` class, the `run` method locks the write lock, performs the write operation, and then unlocks the write lock. - -```java -public class Writer implements Runnable { - - private final Lock writeLock; - private final String name; - private final long writingTime; - - public Writer(String name, Lock writeLock, long writingTime) { - this.name = name; - this.writeLock = writeLock; - this.writingTime = writingTime; - } - - @Override - public void run() { - writeLock.lock(); - try { - write(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when writing", e); - Thread.currentThread().interrupt(); - } finally { - writeLock.unlock(); - } - } - - public void write() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(writingTime); - LOGGER.info("{} finished after writing {}ms", name, writingTime); - } -} -``` - -Finally, we have the `ReadWriteLock` class. This class controls the access to the shared resource. It allows multiple readers to access the resource concurrently if there's no writer that has the lock. On the other hand, it ensures that only one writer can access the resource at a time. - -```java -public class ReadWriteLock implements ReaderWriterLock { - - private final Object readerMutex = new Object(); - private int currentReaderCount; - private final Set globalMutex = new HashSet<>(); - private final ReadLock readerLock = new ReadLock(); - private final WriteLock writerLock = new WriteLock(); - - public Lock readLock() { - return readerLock; - } - - public Lock writeLock() { - return writerLock; - } - - private boolean doesWriterOwnThisLock() { - return globalMutex.contains(writerLock); - } - - private boolean isLockFree() { - return globalMutex.isEmpty(); - } - - private class ReadLock implements Lock { - // Implementation of the read lock - } - - private class WriteLock implements Lock { - // Implementation of the write lock - } -} -``` - -In the `App` class, we create a fixed thread pool and submit `Reader` and `Writer` tasks to it. The `Reader` tasks acquire the read lock to read the shared resource, and the `Writer` tasks acquire the write lock to write to the shared resource. - -## Class diagram - -![Reader-Writer Lock](./etc/reader-writer-lock.png "Reader-Writer Lock") - -## Applicability - -* Use when you need to manage concurrent read and write access to a shared resource. -* Suitable for systems with more frequent read operations than write operations. -* Ideal for situations where read operations can proceed concurrently but write operations require exclusive access. - -## Known Uses - -* Database management systems to allow multiple transactions to read data simultaneously while ensuring exclusive access for data modifications. -* Filesystems to manage concurrent read and write operations on files. -* In-memory caches where read access is predominant over write access. -* [ReentrantReadWriteLock in Java](https://docs.oracle.com/en/java/javase/17/docs//api/java.base/java/util/concurrent/locks/ReentrantReadWriteLock.html) - -## Consequences - -Benefits: - -* Improves performance in scenarios with a high ratio of read operations to write operations. -* Reduces contention and increases concurrency for read operations. - -Trade-offs: - -* More complex to implement compared to simple locks. -* Potential for starvation where write operations could be delayed indefinitely if read operations continue to occur. -* Requires careful handling of thread management and synchronization to avoid deadlocks and ensure data consistency. - -## Related Patterns - -* [Lockable Object](https://java-design-patterns.com/patterns/lockable-object/): Both patterns deal with managing access to shared resources, but Reader-Writer Lock allows higher concurrency for read operations. - -## Credits - -* [Concurrent Programming in Java : Design Principles and Patterns](https://amzn.to/4dIBqxL) -* [Java Concurrency in Practice](https://amzn.to/4aRMruW) -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) -* [Readers–writer lock - Wikipedia](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock) -* [Readers–writers_problem - Wikipedia](https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem) diff --git a/reader-writer-lock/etc/reader-writer-lock.png b/reader-writer-lock/etc/reader-writer-lock.png deleted file mode 100644 index f7b6005309263d2dc8baf7505fd68091a580011b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39623 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 diff --git a/reader-writer-lock/etc/reader-writer-lock.ucls b/reader-writer-lock/etc/reader-writer-lock.ucls deleted file mode 100644 index 920904e76..000000000 --- a/reader-writer-lock/etc/reader-writer-lock.ucls +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/reader-writer-lock/etc/reader-writer-lock.urm.puml b/reader-writer-lock/etc/reader-writer-lock.urm.puml deleted file mode 100644 index f0e33ab3c..000000000 --- a/reader-writer-lock/etc/reader-writer-lock.urm.puml +++ /dev/null @@ -1,65 +0,0 @@ -@startuml -package com.iluwatar.reader.writer.lock { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - class Reader { - - LOGGER : Logger {static} - - name : String - - readLock : Lock - - readingTime : long - + Reader(name : String, readLock : Lock) - + Reader(name : String, readLock : Lock, readingTime : long) - + read() - + run() - } - class ReaderWriterLock { - - LOGGER : Logger {static} - - currentReaderCount : int - - globalMutex : Set - - readerLock : ReadLock - - readerMutex : Object - - writerLock : WriteLock - + ReaderWriterLock() - - doesWriterOwnThisLock() : boolean - - isLockFree() : boolean - + readLock() : Lock - + writeLock() : Lock - } - -class ReadLock { - - ReadLock() - - acquireForReaders() - + lock() - + lockInterruptibly() - + newCondition() : Condition - + tryLock() : boolean - + tryLock(time : long, unit : TimeUnit) : boolean - + unlock() - } - -class WriteLock { - - WriteLock() - + lock() - + lockInterruptibly() - + newCondition() : Condition - + tryLock() : boolean - + tryLock(time : long, unit : TimeUnit) : boolean - + unlock() - } - class Writer { - - LOGGER : Logger {static} - - name : String - - writeLock : Lock - - writingTime : long - + Writer(name : String, writeLock : Lock) - + Writer(name : String, writeLock : Lock, writingTime : long) - + run() - + write() - } -} -ReaderWriterLock --> "-readerLock" ReadLock -ReadLock --+ ReaderWriterLock -WriteLock --+ ReaderWriterLock -ReaderWriterLock --> "-writerLock" WriteLock -@enduml \ No newline at end of file diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml deleted file mode 100644 index 5f0b7b3ac..000000000 --- a/reader-writer-lock/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - reader-writer-lock - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.mockito - mockito-core - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.reader.writer.lock.App - - - - - - - - - diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java deleted file mode 100644 index 48ce50463..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; - -/** - * In a multiple thread applications, the threads may try to synchronize the shared resources - * regardless of read or write operation. It leads to a low performance especially in a "read more - * write less" system as indeed the read operations are thread-safe to another read operation. - * - *

Reader writer lock is a synchronization primitive that try to resolve this problem. This - * pattern allows concurrent access for read-only operations, while write operations require - * exclusive access. This means that multiple threads can read the data in parallel but an exclusive - * lock is needed for writing or modifying data. When a writer is writing the data, all other - * writers or readers will be blocked until the writer is finished writing. - * - *

This example use two mutex to demonstrate the concurrent access of multiple readers and - * writers. - * - * @author hongshuwei@gmail.com - */ -@Slf4j -public class App { - - /** - * Program entry point. - * - * @param args command line args - */ - public static void main(String[] args) { - - var executeService = Executors.newFixedThreadPool(10); - var lock = new ReaderWriterLock(); - - // Start writers - for (var i = 0; i < 5; i++) { - var writingTime = ThreadLocalRandom.current().nextLong(5000); - executeService.submit(new Writer("Writer " + i, lock.writeLock(), writingTime)); - } - LOGGER.info("Writers added..."); - - // Start readers - for (var i = 0; i < 5; i++) { - var readingTime = ThreadLocalRandom.current().nextLong(10); - executeService.submit(new Reader("Reader " + i, lock.readLock(), readingTime)); - } - LOGGER.info("Readers added..."); - - try { - Thread.sleep(5000L); - } catch (InterruptedException e) { - LOGGER.error("Error sleeping before adding more readers", e); - Thread.currentThread().interrupt(); - } - - // Start readers - for (var i = 6; i < 10; i++) { - var readingTime = ThreadLocalRandom.current().nextLong(10); - executeService.submit(new Reader("Reader " + i, lock.readLock(), readingTime)); - } - LOGGER.info("More readers added..."); - - - // In the system console, it can see that the read operations are executed concurrently while - // write operations are exclusive. - executeService.shutdown(); - try { - executeService.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - Thread.currentThread().interrupt(); - } - - } - -} diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java deleted file mode 100644 index a652b8d5f..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.concurrent.locks.Lock; -import lombok.extern.slf4j.Slf4j; - -/** - * Reader class, read when it acquired the read lock. - */ -@Slf4j -public class Reader implements Runnable { - - private final Lock readLock; - - private final String name; - - private final long readingTime; - - /** - * Create new Reader. - * - * @param name - Name of the thread owning the reader - * @param readLock - Lock for this reader - * @param readingTime - amount of time (in milliseconds) for this reader to engage reading - */ - public Reader(String name, Lock readLock, long readingTime) { - this.name = name; - this.readLock = readLock; - this.readingTime = readingTime; - } - - /** - * Create new Reader who reads for 250ms. - * - * @param name - Name of the thread owning the reader - * @param readLock - Lock for this reader - */ - public Reader(String name, Lock readLock) { - this(name, readLock, 250L); - } - - @Override - public void run() { - readLock.lock(); - try { - read(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when reading", e); - Thread.currentThread().interrupt(); - } finally { - readLock.unlock(); - } - } - - /** - * Simulate the read operation. - */ - public void read() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(readingTime); - LOGGER.info("{} finish after reading {}ms", name, readingTime); - } -} diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java deleted file mode 100644 index 4c09b1e69..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import lombok.extern.slf4j.Slf4j; - -/** - * Class responsible for control the access for reader or writer - * - *

Allows multiple readers to hold the lock at same time, but if any writer holds the lock then - * readers wait. If reader holds the lock then writer waits. This lock is not fair. - */ -@Slf4j -public class ReaderWriterLock implements ReadWriteLock { - - - private final Object readerMutex = new Object(); - - private int currentReaderCount; - - /** - * Global mutex is used to indicate that whether reader or writer gets the lock in the moment. - * - *

1. When it contains the reference of {@link #readerLock}, it means that the lock is - * acquired by the reader, another reader can also do the read operation concurrently.
2. - * When it contains the reference of reference of {@link #writerLock}, it means that the lock is - * acquired by the writer exclusively, no more reader or writer can get the lock. - * - *

This is the most important field in this class to control the access for reader/writer. - */ - private final Set globalMutex = new HashSet<>(); - - private final ReadLock readerLock = new ReadLock(); - private final WriteLock writerLock = new WriteLock(); - - @Override - public Lock readLock() { - return readerLock; - } - - @Override - public Lock writeLock() { - return writerLock; - } - - /** - * return true when globalMutex hold the reference of writerLock. - */ - private boolean doesWriterOwnThisLock() { - return globalMutex.contains(writerLock); - } - - /** - * Nobody get the lock when globalMutex contains nothing. - */ - private boolean isLockFree() { - return globalMutex.isEmpty(); - } - - /** - * Reader Lock, can be access for more than one reader concurrently if no writer get the lock. - */ - private class ReadLock implements Lock { - - @Override - public void lock() { - synchronized (readerMutex) { - currentReaderCount++; - if (currentReaderCount == 1) { - acquireForReaders(); - } - } - } - - /** - * Acquire the globalMutex lock on behalf of current and future concurrent readers. Make sure no - * writers currently owns the lock. - */ - private void acquireForReaders() { - // Try to get the globalMutex lock for the first reader - synchronized (globalMutex) { - // If the no one get the lock or the lock is locked by reader, just set the reference - // to the globalMutex to indicate that the lock is locked by Reader. - while (doesWriterOwnThisLock()) { - try { - globalMutex.wait(); - } catch (InterruptedException e) { - var message = "InterruptedException while waiting for globalMutex in acquireForReaders"; - LOGGER.info(message, e); - Thread.currentThread().interrupt(); - } - } - globalMutex.add(this); - } - } - - @Override - public void unlock() { - synchronized (readerMutex) { - currentReaderCount--; - // Release the lock only when it is the last reader, it is ensure that the lock is released - // when all reader is completely. - if (currentReaderCount == 0) { - synchronized (globalMutex) { - // Notify the waiter, mostly the writer - globalMutex.remove(this); - globalMutex.notifyAll(); - } - } - } - - } - - @Override - public void lockInterruptibly() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock(long time, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - - @Override - public Condition newCondition() { - throw new UnsupportedOperationException(); - } - - } - - /** - * Writer Lock, can only be accessed by one writer concurrently. - */ - private class WriteLock implements Lock { - - @Override - public void lock() { - synchronized (globalMutex) { - - // Wait until the lock is free. - while (!isLockFree()) { - try { - globalMutex.wait(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException while waiting for globalMutex to begin writing", e); - Thread.currentThread().interrupt(); - } - } - // When the lock is free, acquire it by placing an entry in globalMutex - globalMutex.add(this); - } - } - - @Override - public void unlock() { - synchronized (globalMutex) { - globalMutex.remove(this); - // Notify the waiter, other writer or reader - globalMutex.notifyAll(); - } - } - - @Override - public void lockInterruptibly() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock(long time, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - - @Override - public Condition newCondition() { - throw new UnsupportedOperationException(); - } - } - -} diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java deleted file mode 100644 index 762f8f281..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.concurrent.locks.Lock; -import lombok.extern.slf4j.Slf4j; - -/** - * Writer class, write when it acquired the write lock. - */ -@Slf4j -public class Writer implements Runnable { - - private final Lock writeLock; - - private final String name; - - private final long writingTime; - - /** - * Create new Writer who writes for 250ms. - * - * @param name - Name of the thread owning the writer - * @param writeLock - Lock for this writer - */ - public Writer(String name, Lock writeLock) { - this(name, writeLock, 250L); - } - - /** - * Create new Writer. - * - * @param name - Name of the thread owning the writer - * @param writeLock - Lock for this writer - * @param writingTime - amount of time (in milliseconds) for this reader to engage writing - */ - public Writer(String name, Lock writeLock, long writingTime) { - this.name = name; - this.writeLock = writeLock; - this.writingTime = writingTime; - } - - - @Override - public void run() { - writeLock.lock(); - try { - write(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when writing", e); - Thread.currentThread().interrupt(); - } finally { - writeLock.unlock(); - } - } - - /** - * Simulate the write operation. - */ - public void write() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(writingTime); - LOGGER.info("{} finished after writing {}ms", name, writingTime); - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java deleted file mode 100644 index 9dbaced75..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - -/** - * Application test - */ -class AppTest { - - @Test - void shouldExecuteWithoutException() { - assertDoesNotThrow(() -> App.main(new String[]{})); - - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderAndWriterTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderAndWriterTest.java deleted file mode 100644 index bc1716146..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderAndWriterTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author hongshuwei@gmail.com - */ -class ReaderAndWriterTest { - - private InMemoryAppender appender; - - @BeforeEach - void setUp() { - appender = new InMemoryAppender(); - } - - @AfterEach - void tearDown() { - appender.stop(); - } - - private static final Logger LOGGER = LoggerFactory.getLogger(ReaderAndWriterTest.class); - - /** - * Verify reader and writer can only get the lock to read and write orderly - */ - @Test - void testReadAndWrite() throws Exception { - - var lock = new ReaderWriterLock(); - - var reader1 = new Reader("Reader 1", lock.readLock()); - var writer1 = new Writer("Writer 1", lock.writeLock()); - - var executeService = Executors.newFixedThreadPool(2); - executeService.submit(reader1); - // Let reader1 execute first - Thread.sleep(150); - executeService.submit(writer1); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - - assertTrue(appender.logContains("Reader 1 begin")); - assertTrue(appender.logContains("Reader 1 finish")); - assertTrue(appender.logContains("Writer 1 begin")); - assertTrue(appender.logContains("Writer 1 finish")); - } - - /** - * Verify reader and writer can only get the lock to read and write orderly - */ - @Test - void testWriteAndRead() throws Exception { - - var executeService = Executors.newFixedThreadPool(2); - var lock = new ReaderWriterLock(); - - var reader1 = new Reader("Reader 1", lock.readLock()); - var writer1 = new Writer("Writer 1", lock.writeLock()); - - executeService.submit(writer1); - // Let writer1 execute first - Thread.sleep(150); - executeService.submit(reader1); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - - assertTrue(appender.logContains("Writer 1 begin")); - assertTrue(appender.logContains("Writer 1 finish")); - assertTrue(appender.logContains("Reader 1 begin")); - assertTrue(appender.logContains("Reader 1 finish")); - } -} - diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderTest.java deleted file mode 100644 index 2fb31f36c..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.spy; - -import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author hongshuwei@gmail.com - */ -class ReaderTest { - - private InMemoryAppender appender; - - @BeforeEach - void setUp() { - appender = new InMemoryAppender(Reader.class); - } - - @AfterEach - void tearDown() { - appender.stop(); - } - - private static final Logger LOGGER = LoggerFactory.getLogger(ReaderTest.class); - - /** - * Verify that multiple readers can get the read lock concurrently - */ - @Test - void testRead() throws Exception { - - var executeService = Executors.newFixedThreadPool(2); - var lock = new ReaderWriterLock(); - - var reader1 = spy(new Reader("Reader 1", lock.readLock())); - var reader2 = spy(new Reader("Reader 2", lock.readLock())); - - executeService.submit(reader1); - Thread.sleep(150); - executeService.submit(reader2); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - - // Read operation will hold the read lock 250 milliseconds, so here we prove that multiple reads - // can be performed in the same time. - assertTrue(appender.logContains("Reader 1 begin")); - assertTrue(appender.logContains("Reader 2 begin")); - assertTrue(appender.logContains("Reader 1 finish")); - assertTrue(appender.logContains("Reader 2 finish")); - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/WriterTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/WriterTest.java deleted file mode 100644 index 9c8422c0f..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/WriterTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.spy; - -import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author hongshuwei@gmail.com - */ -class WriterTest { - - private InMemoryAppender appender; - - @BeforeEach - void setUp() { - appender = new InMemoryAppender(Writer.class); - } - - @AfterEach - void tearDown() { - appender.stop(); - } - - private static final Logger LOGGER = LoggerFactory.getLogger(WriterTest.class); - - /** - * Verify that multiple writers will get the lock in order. - */ - @Test - void testWrite() throws Exception { - - var executeService = Executors.newFixedThreadPool(2); - var lock = new ReaderWriterLock(); - - var writer1 = spy(new Writer("Writer 1", lock.writeLock())); - var writer2 = spy(new Writer("Writer 2", lock.writeLock())); - - executeService.submit(writer1); - // Let write1 execute first - Thread.sleep(150); - executeService.submit(writer2); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - // Write operation will hold the write lock 250 milliseconds, so here we verify that when two - // writer execute concurrently, the second writer can only writes only when the first one is - // finished. - assertTrue(appender.logContains("Writer 1 begin")); - assertTrue(appender.logContains("Writer 1 finish")); - assertTrue(appender.logContains("Writer 2 begin")); - assertTrue(appender.logContains("Writer 2 finish")); - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java deleted file mode 100644 index f349ea382..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). - * - * The MIT License - * Copyright © 2014-2022 Ilkka Seppälä - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.iluwatar.reader.writer.lock.utils; - -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.AppenderBase; -import java.util.LinkedList; -import java.util.List; -import org.slf4j.LoggerFactory; - -/** - * InMemory Log Appender Util. - */ -public class InMemoryAppender extends AppenderBase { - private final List log = new LinkedList<>(); - - public InMemoryAppender(Class clazz) { - ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); - start(); - } - - public InMemoryAppender() { - ((Logger) LoggerFactory.getLogger("root")).addAppender(this); - start(); - } - - @Override - protected void append(ILoggingEvent eventObject) { - log.add(eventObject); - } - - public boolean logContains(String message) { - return log.stream().anyMatch(event -> event.getFormattedMessage().contains(message)); - } -} diff --git a/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java b/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java index 9432480d6..37ba92660 100644 --- a/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java +++ b/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java @@ -23,6 +23,8 @@ * THE SOFTWARE. */ package com.iluwatar.serializedentity; +import java.nio.file.Files; +import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -101,5 +103,10 @@ public class CountryTest { } catch (Exception e) { LOGGER.error("Error occurred: ", e); } + try { + Files.deleteIfExists(Paths.get("output.txt")); + } catch (IOException e) { + LOGGER.error("Error occurred: ", e); + } } } diff --git a/type-object/etc/type-object.urm.puml b/type-object/etc/type-object.urm.puml new file mode 100644 index 000000000..42ac137e8 --- /dev/null +++ b/type-object/etc/type-object.urm.puml @@ -0,0 +1,77 @@ +@startuml +package com.iluwatar.typeobject { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Candy { + ~ name : String + ~ parent : Candy + ~ parentName : String + - points : int + - type : Type + ~ Candy(name : String, parentName : String, type : Type, points : int) + ~ getName() : String + ~ getParent() : Candy + ~ getParentName() : String + ~ getPoints() : int + ~ getType() : Type + + setPoints(points : int) + } + ~enum Type { + + CRUSHABLE_CANDY {static} + + REWARD_FRUIT {static} + + valueOf(name : String) : Type {static} + + values() : Type[] {static} + } + class CandyGame { + - LOGGER : Logger {static} + ~ cells : Cell[][] + ~ pool : CellPool + ~ totalPoints : int + ~ CandyGame(num : int, pool : CellPool) + ~ adjacentCells(y : int, x : int) : List + ~ continueRound() : boolean + ~ handleChange(points : int) + ~ numOfSpaces(num : int) : String {static} + ~ printGameStatus() + ~ round(timeSoFar : int, totalTime : int) + } + class Cell { + ~ candy : Candy + ~ positionX : int + ~ positionY : int + + Cell() + + Cell(candy : Candy, positionX : int, positionY : int) + ~ crush(pool : CellPool, cellMatrix : Cell[][]) + ~ fillThisSpace(pool : CellPool, cellMatrix : Cell[][]) + ~ handleCrush(c : Cell, pool : CellPool, cellMatrix : Cell[][]) + ~ interact(c : Cell, pool : CellPool, cellMatrix : Cell[][]) : int + } + class CellPool { + + CANDY : String {static} + + FRUIT : String {static} + - LOGGER : Logger {static} + - RANDOM : SecureRandom {static} + ~ pointer : int + ~ pool : List + ~ randomCode : Candy[] + ~ CellPool(num : int) + ~ addNewCell(c : Cell) + ~ assignRandomCandytypes() : Candy[] + ~ getNewCell() : Cell + } + class JsonParser { + ~ candies : Hashtable + ~ JsonParser() + ~ parse() + ~ setParentAndPoints() + } +} +Candy --> "-type" Type +Cell --> "-candy" Candy +Candy --> "-parent" Candy +CandyGame --> "-pool" CellPool +CellPool --> "-pool" Cell +@enduml \ No newline at end of file