diff --git a/Microservice-pattern-Domain-event/README.md b/Microservice-pattern-Domain-event/README.md
new file mode 100644
index 000000000000..ed7e9d37c7c5
--- /dev/null
+++ b/Microservice-pattern-Domain-event/README.md
@@ -0,0 +1,153 @@
+# Microservice Pattern: Domain Event
+
+## Overview
+The Domain Event design pattern enables reliable communication between microservices in a decoupled manner. This pattern allows services to react to state changes in other services without tightly coupling them, enhancing scalability and maintainability.
+
+## Intent of the Domain Event Pattern
+The Domain Event pattern decouples services by allowing one service to notify others of significant state changes. When an important change occurs, a domain event is published, and other services can listen and react to it.
+
+## Detailed Explanation
+
+### Real-World Example
+In an e-commerce system, when a customer places an order, the `OrderService` creates an `OrderCreatedEvent`. This event is published, and other services like Inventory and Payment can listen for it and act accordingly (e.g., updating inventory, processing payment).
+
+### In Plain Words
+When an important event happens in one service (e.g., order creation), it publishes a Domain Event. Other services can subscribe to these events and react without directly communicating with each other.
+
+---
+
+## Example of the Domain Event Pattern in Action
+
+Consider a system with the following services:
+- **OrderService**: Creates orders.
+- **InventoryService**: Updates stock based on orders.
+- **PaymentService**: Processes payments after order creation.
+
+When an order is created in the `OrderService`, an `OrderCreatedEvent` is published. Other services listen for this event and act accordingly.
+
+---
+
+## Implementation in Java
+
+### 1. Domain Event Class
+This class serves as the base for all domain events and includes the timestamp.
+
+```java
+public abstract class DomainEvent {
+ private final LocalDateTime timestamp;
+
+ public DomainEvent() {
+ this.timestamp = LocalDateTime.now();
+ }
+
+ public LocalDateTime getTimestamp() {
+ return timestamp;
+ }
+}
+```
+### 2. Event Publisher
+The `EventPublisher` component is responsible for publishing domain events.
+
+```java
+@Component
+public class EventPublisher {
+ private final ApplicationEventPublisher applicationEventPublisher;
+
+ public EventPublisher(ApplicationEventPublisher applicationEventPublisher) {
+ this.applicationEventPublisher = applicationEventPublisher;
+ }
+
+ public void publish(DomainEvent event) {
+ applicationEventPublisher.publishEvent(event);
+ }
+}
+
+```
+### 3. Event Listener
+The `OrderCreatedListener` listens for the `OrderCreatedEvent` and processes it when it occurs.
+
+```java
+@Component
+public class OrderCreatedListener {
+ @EventListener
+ public void handleOrderCreatedEvent(OrderCreatedEvent event) {
+ System.out.println("Handling Order Created Event: " + event.getOrderId());
+ // Example logic: Notify another service or update the database
+ }
+}
+```
+
+### 4. Order Service
+The `OrderService` publishes the `OrderCreatedEvent` when an order is created.
+
+```java
+@Service
+public class OrderService {
+ private final EventPublisher eventPublisher;
+
+ public OrderService(EventPublisher eventPublisher) {
+ this.eventPublisher = eventPublisher;
+ }
+
+ public void createOrder(String orderId) {
+ System.out.println("Order created with ID: " + orderId);
+ OrderCreatedEvent event = new OrderCreatedEvent(orderId);
+ eventPublisher.publish(event);
+ }
+}
+```
+
+### 5. Order Created Event
+The `OrderCreatedEvent` extends `DomainEvent` and represents the creation of an order.
+
+```java
+public class OrderCreatedEvent extends DomainEvent {
+ private final String orderId;
+
+ public OrderCreatedEvent(String orderId) {
+ this.orderId = orderId;
+ }
+
+ public String getOrderId() {
+ return orderId;
+ }
+}
+
+```
+### 6. When to Use the Domain Event Pattern
+This pattern is ideal for scenarios where:
+- Services need to react to state changes in other services without tight coupling.
+- Asynchronous communication between services is preferred.
+- Scalability is crucial, allowing services to independently scale and evolve.
+
+---
+
+### 7. Benefits and Trade-offs of the Domain Event Pattern
+
+#### Benefits:
+1. **Decoupling**: Services are decoupled, making maintenance and independent scaling easier.
+2. **Scalability**: Services scale independently, based on individual requirements.
+3. **Asynchronous Processing**: Event-driven communication supports asynchronous workflows, enhancing system responsiveness.
+
+#### Trade-offs:
+1. **Eventual Consistency**: As events are processed asynchronously, eventual consistency must be handled carefully.
+2. **Complexity**: Adding events and listeners increases system complexity, particularly for failure handling and retries.
+3. **Debugging**: Asynchronous and decoupled communication can make tracing data flow across services more challenging.
+
+---
+
+### 8. Example Flow
+
+1. **Order Created**: The `OrderService` creates a new order.
+2. **Publish Event**: The `OrderCreatedEvent` is published by the `EventPublisher`.
+3. **Event Listener**: The `OrderCreatedListener` listens for the event and executes relevant logic (e.g., notifying other services).
+4. **Outcome**: Other services (e.g., Inventory, Payment) react to the event accordingly.
+
+---
+
+### 9. References and Credits
+- *Domain-Driven Design* by Eric Evans
+- *Building Microservices* by Sam Newman
+- *Microservices Patterns* by Chris Richardson
+
+For more information on Domain Event patterns and best practices, refer to the above books.
diff --git a/Microservice-pattern-Domain-event/pom.xml b/Microservice-pattern-Domain-event/pom.xml
new file mode 100644
index 000000000000..46350473166d
--- /dev/null
+++ b/Microservice-pattern-Domain-event/pom.xml
@@ -0,0 +1,73 @@
+
+ 4.0.0
+
+ com.iluwatar
+ Microservice-pattern-Domain-event
+ 1.0-SNAPSHOT
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.1.0
+
+
+
+
+ 17
+ ${java.version}
+ ${java.version}
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ org.springframework
+ spring-context
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/DomainEvent.java b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/DomainEvent.java
new file mode 100644
index 000000000000..3e3c61f9c418
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/DomainEvent.java
@@ -0,0 +1,15 @@
+package com.iluwatar;
+
+import java.time.LocalDateTime;
+
+public abstract class DomainEvent {
+ private final LocalDateTime timestamp;
+
+ public DomainEvent() {
+ this.timestamp = LocalDateTime.now();
+ }
+
+ public LocalDateTime getTimestamp() {
+ return timestamp;
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/EventPublisher.java b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/EventPublisher.java
new file mode 100644
index 000000000000..ea74d3b9373a
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/EventPublisher.java
@@ -0,0 +1,12 @@
+package com.iluwatar;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class EventPublisher {
+
+ public void publishEvent(OrderCreatedEvent event) {
+ // Simulate publishing the event
+ System.out.println("Event published: " + event.getOrderId());
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/Main.java b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/Main.java
new file mode 100644
index 000000000000..df91ebd713bf
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/Main.java
@@ -0,0 +1,15 @@
+package com.iluwatar;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Main {
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class, args);
+
+ // Simulate creating an order
+ OrderService orderService = SpringContext.getBean(OrderService.class);
+ orderService.createOrder("12345");
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderCreatedEvent.java b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderCreatedEvent.java
new file mode 100644
index 000000000000..ad6c165606be
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderCreatedEvent.java
@@ -0,0 +1,14 @@
+package com.iluwatar;
+
+public class OrderCreatedEvent {
+
+ private final String orderId;
+
+ public OrderCreatedEvent(String orderId) {
+ this.orderId = orderId;
+ }
+
+ public String getOrderId() {
+ return orderId;
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderCreatedListener.java b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderCreatedListener.java
new file mode 100644
index 000000000000..812c0849322e
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderCreatedListener.java
@@ -0,0 +1,21 @@
+package com.iluwatar;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class OrderCreatedListener {
+
+ private final EventPublisher eventPublisher;
+
+ @Autowired
+ public OrderCreatedListener(EventPublisher eventPublisher) {
+ this.eventPublisher = eventPublisher;
+ }
+
+ public void handleOrderCreatedEvent(OrderCreatedEvent event) {
+ // Process the event
+ System.out.println("Processing order: " + event.getOrderId());
+ eventPublisher.publishEvent(event);
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderService.java b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderService.java
new file mode 100644
index 000000000000..6066242d0c61
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/OrderService.java
@@ -0,0 +1,20 @@
+package com.iluwatar;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class OrderService {
+
+ private final OrderCreatedListener orderCreatedListener;
+
+ @Autowired
+ public OrderService(OrderCreatedListener orderCreatedListener) {
+ this.orderCreatedListener = orderCreatedListener;
+ }
+
+ public void createOrder(String orderId) {
+ OrderCreatedEvent event = new OrderCreatedEvent(orderId);
+ orderCreatedListener.handleOrderCreatedEvent(event);
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/SpringContext.java b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/SpringContext.java
new file mode 100644
index 000000000000..a18290590a2f
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/main/java/com/iluwatar/SpringContext.java
@@ -0,0 +1,17 @@
+package com.iluwatar;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringContext {
+ private static ApplicationContext context;
+
+ public SpringContext(ApplicationContext applicationContext) {
+ context = applicationContext;
+ }
+
+ public static T getBean(Class beanClass) {
+ return context.getBean(beanClass);
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/EventPublisher.java b/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/EventPublisher.java
new file mode 100644
index 000000000000..7dc5f93b86b1
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/EventPublisher.java
@@ -0,0 +1,15 @@
+package com.iluwatar;
+
+import org.junit.jupiter.api.Test;
+
+import static org.mockito.Mockito.*;
+
+class EventPublisherTest {
+
+ @Test
+ void testPublishEvent() {
+ EventPublisher eventPublisher = new EventPublisher();
+ OrderCreatedEvent event = new OrderCreatedEvent("12345");
+ eventPublisher.publishEvent(event);
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/OrderCreatedListenerTest.java b/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/OrderCreatedListenerTest.java
new file mode 100644
index 000000000000..7057a283dfa8
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/OrderCreatedListenerTest.java
@@ -0,0 +1,36 @@
+package com.iluwatar;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+@SpringBootTest
+public class OrderCreatedListenerTest {
+
+ @InjectMocks
+ private OrderCreatedListener orderCreatedListener;
+
+ @MockBean
+ private EventPublisher eventPublisher;
+
+ @Test
+ public void testHandleOrderCreatedEvent() {
+ // Arrange
+ String orderId = "order123";
+ OrderCreatedEvent event = new OrderCreatedEvent(orderId);
+
+ // Act
+ orderCreatedListener.handleOrderCreatedEvent(event);
+
+ // Assert
+ verify(eventPublisher, times(1)).publishEvent(event);
+ }
+}
diff --git a/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/OrderService.java b/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/OrderService.java
new file mode 100644
index 000000000000..e330b1d6301b
--- /dev/null
+++ b/Microservice-pattern-Domain-event/src/test/java/com/iluwatar/OrderService.java
@@ -0,0 +1,34 @@
+package com.iluwatar;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.*;
+
+class OrderServiceTest {
+
+ @Mock
+ private EventPublisher eventPublisher;
+
+ private OrderService orderService;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this); // Initialize mocks
+ orderService = new OrderService(new OrderCreatedListener(eventPublisher));
+ }
+
+ @Test
+ void testCreateOrderPublishesEvent() {
+ // Arrange
+ String orderId = "123";
+
+ // Act
+ orderService.createOrder(orderId);
+
+ // Assert
+ verify(eventPublisher, times(1)).publishEvent(any(OrderCreatedEvent.class));
+ }
+}
diff --git a/fluent-interface/etc/fluent-interface.urm.puml b/fluent-interface/etc/fluent-interface.urm.puml
new file mode 100644
index 000000000000..d343a478bff0
--- /dev/null
+++ b/fluent-interface/etc/fluent-interface.urm.puml
@@ -0,0 +1,72 @@
+@startuml
+package com.iluwatar.fluentinterface.fluentiterable.simple {
+ class SimpleFluentIterable {
+ - iterable : Iterable
+ + SimpleFluentIterable(iterable : Iterable)
+ + asList() : List
+ + filter(predicate : Predicate super E>) : FluentIterable
+ + first() : Optional
+ + first(count : int) : FluentIterable
+ + forEach(action : Consumer super E>)
+ + from(iterable : Iterable) : FluentIterable {static}
+ + fromCopyOf(iterable : Iterable) : FluentIterable {static}
+ + getRemainingElementsCount() : int
+ + iterator() : Iterator
+ + last() : Optional
+ + last(count : int) : FluentIterable
+ + map(function : Function super E, T>) : FluentIterable
+ + spliterator() : Spliterator
+ + toList(iterator : Iterator) : List {static}
+ }
+}
+package com.iluwatar.fluentinterface.app {
+ class App {
+ - LOGGER : Logger {static}
+ + App()
+ + main(args : String[]) {static}
+ - negatives() : Predicate super Integer> {static}
+ - positives() : Predicate super Integer> {static}
+ - prettyPrint(delimiter : String, prefix : String, iterable : Iterable) {static}
+ - prettyPrint(prefix : String, iterable : Iterable) {static}
+ - transformToString() : Function {static}
+ }
+}
+package com.iluwatar.fluentinterface.fluentiterable.lazy {
+ abstract class DecoratingIterator {
+ # fromIterator : Iterator
+ - next : E
+ + DecoratingIterator(fromIterator : Iterator)
+ + computeNext() : E {abstract}
+ + hasNext() : boolean
+ + next() : E
+ }
+ class LazyFluentIterable {
+ - iterable : Iterable
+ # LazyFluentIterable()
+ + LazyFluentIterable(iterable : Iterable)
+ + asList() : List
+ + filter(predicate : Predicate super E>) : FluentIterable
+ + first() : Optional
+ + first(count : int) : FluentIterable
+ + from(iterable : Iterable) : FluentIterable {static}
+ + iterator() : Iterator
+ + last() : Optional
+ + last(count : int) : FluentIterable
+ + map(function : Function super E, T>) : FluentIterable
+ }
+}
+package com.iluwatar.fluentinterface.fluentiterable {
+ interface FluentIterable {
+ + asList() : List {abstract}
+ + copyToList(iterable : Iterable) : List {static}
+ + filter(Predicate super E>) : FluentIterable {abstract}
+ + first() : Optional {abstract}
+ + first(int) : FluentIterable {abstract}
+ + last() : Optional {abstract}
+ + last(int) : FluentIterable {abstract}
+ + map(Function super E, T>) : FluentIterable {abstract}
+ }
+}
+LazyFluentIterable ..|> FluentIterable
+SimpleFluentIterable ..|> FluentIterable
+@enduml
\ No newline at end of file
diff --git a/function-composition/etc/function-composition.urm.puml b/function-composition/etc/function-composition.urm.puml
new file mode 100644
index 000000000000..79b2a898fd12
--- /dev/null
+++ b/function-composition/etc/function-composition.urm.puml
@@ -0,0 +1,12 @@
+@startuml
+package com.iluwatar.function.composition {
+ class App {
+ + App()
+ + main(args : String[]) {static}
+ }
+ class FunctionComposer {
+ + FunctionComposer()
+ + composeFunctions(f1 : Function, f2 : Function) : Function {static}
+ }
+}
+@enduml
\ No newline at end of file
diff --git a/hexagonal-architecture/etc/hexagonal-architecture.urm.puml b/hexagonal-architecture/etc/hexagonal-architecture.urm.puml
new file mode 100644
index 000000000000..5849b24adbae
--- /dev/null
+++ b/hexagonal-architecture/etc/hexagonal-architecture.urm.puml
@@ -0,0 +1,282 @@
+@startuml
+package com.iluwatar.hexagonal.sampledata {
+ class SampleData {
+ - PLAYERS : List {static}
+ - RANDOM : SecureRandom {static}
+ + SampleData()
+ - getRandomPlayerDetails() : PlayerDetails {static}
+ + submitTickets(lotteryService : LotteryService, numTickets : int) {static}
+ }
+}
+package com.iluwatar.hexagonal.service {
+ class ConsoleLottery {
+ - LOGGER : Logger {static}
+ + ConsoleLottery()
+ + main(args : String[]) {static}
+ - printMainMenu() {static}
+ - readString(scanner : Scanner) : String {static}
+ }
+ interface LotteryConsoleService {
+ + addFundsToLotteryAccount(WireTransfers, Scanner) {abstract}
+ + checkTicket(LotteryService, Scanner) {abstract}
+ + queryLotteryAccountFunds(WireTransfers, Scanner) {abstract}
+ + submitTicket(LotteryService, Scanner) {abstract}
+ }
+ class LotteryConsoleServiceImpl {
+ - logger : Logger
+ + LotteryConsoleServiceImpl(logger : Logger)
+ + addFundsToLotteryAccount(bank : WireTransfers, scanner : Scanner)
+ + checkTicket(service : LotteryService, scanner : Scanner)
+ + queryLotteryAccountFunds(bank : WireTransfers, scanner : Scanner)
+ - readString(scanner : Scanner) : String
+ + submitTicket(service : LotteryService, scanner : Scanner)
+ }
+}
+package com.iluwatar.hexagonal.mongo {
+ class MongoConnectionPropertiesLoader {
+ - DEFAULT_HOST : String {static}
+ - DEFAULT_PORT : int {static}
+ - LOGGER : Logger {static}
+ + MongoConnectionPropertiesLoader()
+ + load() {static}
+ }
+}
+package com.iluwatar.hexagonal.domain {
+ class LotteryAdministration {
+ - notifications : LotteryEventLog
+ - repository : LotteryTicketRepository
+ - wireTransfers : WireTransfers
+ + LotteryAdministration(repository : LotteryTicketRepository, notifications : LotteryEventLog, wireTransfers : WireTransfers)
+ + getAllSubmittedTickets() : Map
+ + performLottery() : LotteryNumbers
+ + resetLottery()
+ }
+ class LotteryConstants {
+ + PLAYER_MAX_BALANCE : int {static}
+ + PRIZE_AMOUNT : int {static}
+ + SERVICE_BANK_ACCOUNT : String {static}
+ + SERVICE_BANK_ACCOUNT_BALANCE : int {static}
+ + TICKET_PRIZE : int {static}
+ - LotteryConstants()
+ }
+ class LotteryNumbers {
+ + MAX_NUMBER : int {static}
+ + MIN_NUMBER : int {static}
+ + NUM_NUMBERS : int {static}
+ - numbers : Set
+ - LotteryNumbers()
+ - LotteryNumbers(givenNumbers : Set)
+ # canEqual(other : Object) : boolean
+ + create(givenNumbers : Set) : LotteryNumbers {static}
+ + createRandom() : LotteryNumbers {static}
+ + equals(o : Object) : boolean
+ - generateRandomNumbers()
+ + getNumbers() : Set
+ + getNumbersAsString() : String
+ + hashCode() : int
+ + toString() : String
+ }
+ -class RandomNumberGenerator {
+ - randomIterator : OfInt
+ + RandomNumberGenerator(min : int, max : int)
+ + nextInt() : int
+ }
+ class LotteryService {
+ - notifications : LotteryEventLog
+ - repository : LotteryTicketRepository
+ - wireTransfers : WireTransfers
+ + LotteryService(repository : LotteryTicketRepository, notifications : LotteryEventLog, wireTransfers : WireTransfers)
+ + checkTicketForPrize(id : LotteryTicketId, winningNumbers : LotteryNumbers) : LotteryTicketCheckResult
+ + submitTicket(ticket : LotteryTicket) : Optional
+ }
+ class LotteryTicketCheckResult {
+ - prizeAmount : int
+ - result : CheckResult
+ + LotteryTicketCheckResult(result : CheckResult)
+ + LotteryTicketCheckResult(result : CheckResult, prizeAmount : int)
+ # canEqual(other : Object) : boolean
+ + equals(o : Object) : boolean
+ + getPrizeAmount() : int
+ + getResult() : CheckResult
+ + hashCode() : int
+ }
+ enum CheckResult {
+ + NO_PRIZE {static}
+ + TICKET_NOT_SUBMITTED {static}
+ + WIN_PRIZE {static}
+ + valueOf(name : String) : CheckResult {static}
+ + values() : CheckResult[] {static}
+ }
+ class LotteryTicketId {
+ - id : int
+ - numAllocated : AtomicInteger {static}
+ + LotteryTicketId()
+ + LotteryTicketId(id : int)
+ # canEqual(other : Object) : boolean
+ + equals(o : Object) : boolean
+ + getId() : int
+ + hashCode() : int
+ + toString() : String
+ }
+ class LotteryUtils {
+ - LotteryUtils()
+ + checkTicketForPrize(repository : LotteryTicketRepository, id : LotteryTicketId, winningNumbers : LotteryNumbers) : LotteryTicketCheckResult {static}
+ }
+}
+package com.iluwatar.hexagonal.banking {
+ class InMemoryBank {
+ - accounts : Map {static}
+ + InMemoryBank()
+ + getFunds(bankAccount : String) : int
+ + setFunds(bankAccount : String, amount : int)
+ + transferFunds(amount : int, sourceAccount : String, destinationAccount : String) : boolean
+ }
+ class MongoBank {
+ - DEFAULT_ACCOUNTS_COLLECTION : String {static}
+ - DEFAULT_DB : String {static}
+ - accountsCollection : MongoCollection
+ - database : MongoDatabase
+ - mongoClient : MongoClient
+ + MongoBank()
+ + MongoBank(dbName : String, accountsCollectionName : String)
+ + connect()
+ + connect(dbName : String, accountsCollectionName : String)
+ + getAccountsCollection() : MongoCollection
+ + getDatabase() : MongoDatabase
+ + getFunds(bankAccount : String) : int
+ + getMongoClient() : MongoClient
+ + setFunds(bankAccount : String, amount : int)
+ + transferFunds(amount : int, sourceAccount : String, destinationAccount : String) : boolean
+ }
+ interface WireTransfers {
+ + getFunds(String) : int {abstract}
+ + setFunds(String, int) {abstract}
+ + transferFunds(int, String, String) : boolean {abstract}
+ }
+}
+package com.iluwatar.hexagonal.database {
+ class InMemoryTicketRepository {
+ - tickets : Map {static}
+ + InMemoryTicketRepository()
+ + deleteAll()
+ + findAll() : Map
+ + findById(id : LotteryTicketId) : Optional
+ + save(ticket : LotteryTicket) : Optional
+ }
+ interface LotteryTicketRepository {
+ + deleteAll() {abstract}
+ + findAll() : Map {abstract}
+ + findById(LotteryTicketId) : Optional {abstract}
+ + save(LotteryTicket) : Optional {abstract}
+ }
+ class MongoTicketRepository {
+ - DEFAULT_COUNTERS_COLLECTION : String {static}
+ - DEFAULT_DB : String {static}
+ - DEFAULT_TICKETS_COLLECTION : String {static}
+ - TICKET_ID : String {static}
+ - countersCollection : MongoCollection
+ - database : MongoDatabase
+ - mongoClient : MongoClient
+ - ticketsCollection : MongoCollection
+ + MongoTicketRepository()
+ + MongoTicketRepository(dbName : String, ticketsCollectionName : String, countersCollectionName : String)
+ + connect()
+ + connect(dbName : String, ticketsCollectionName : String, countersCollectionName : String)
+ + deleteAll()
+ - docToTicket(doc : Document) : LotteryTicket
+ + findAll() : Map
+ + findById(id : LotteryTicketId) : Optional
+ + getCountersCollection() : MongoCollection
+ + getNextId() : int
+ + getTicketsCollection() : MongoCollection
+ - initCounters()
+ + save(ticket : LotteryTicket) : Optional
+ }
+}
+package com.iluwatar.hexagonal {
+ class App {
+ + App()
+ + main(args : String[]) {static}
+ }
+}
+package com.iluwatar.hexagonal.administration {
+ class ConsoleAdministration {
+ - LOGGER : Logger {static}
+ + ConsoleAdministration()
+ + main(args : String[]) {static}
+ - printMainMenu() {static}
+ - readString(scanner : Scanner) : String {static}
+ }
+ interface ConsoleAdministrationSrv {
+ + getAllSubmittedTickets() {abstract}
+ + performLottery() {abstract}
+ + resetLottery() {abstract}
+ }
+ class ConsoleAdministrationSrvImpl {
+ - administration : LotteryAdministration
+ - logger : Logger
+ + ConsoleAdministrationSrvImpl(administration : LotteryAdministration, logger : Logger)
+ + getAllSubmittedTickets()
+ + performLottery()
+ + resetLottery()
+ }
+}
+package com.iluwatar.hexagonal.eventlog {
+ interface LotteryEventLog {
+ + prizeError(PlayerDetails, int) {abstract}
+ + ticketDidNotWin(PlayerDetails) {abstract}
+ + ticketSubmitError(PlayerDetails) {abstract}
+ + ticketSubmitted(PlayerDetails) {abstract}
+ + ticketWon(PlayerDetails, int) {abstract}
+ }
+ class MongoEventLog {
+ - DEFAULT_DB : String {static}
+ - DEFAULT_EVENTS_COLLECTION : String {static}
+ - EMAIL : String {static}
+ + MESSAGE : String {static}
+ - PHONE : String {static}
+ - database : MongoDatabase
+ - eventsCollection : MongoCollection
+ - mongoClient : MongoClient
+ - stdOutEventLog : StdOutEventLog
+ + MongoEventLog()
+ + MongoEventLog(dbName : String, eventsCollectionName : String)
+ + connect()
+ + connect(dbName : String, eventsCollectionName : String)
+ + getDatabase() : MongoDatabase
+ + getEventsCollection() : MongoCollection
+ + getMongoClient() : MongoClient
+ + prizeError(details : PlayerDetails, prizeAmount : int)
+ + ticketDidNotWin(details : PlayerDetails)
+ + ticketSubmitError(details : PlayerDetails)
+ + ticketSubmitted(details : PlayerDetails)
+ + ticketWon(details : PlayerDetails, prizeAmount : int)
+ }
+ class StdOutEventLog {
+ - LOGGER : Logger {static}
+ + StdOutEventLog()
+ + prizeError(details : PlayerDetails, prizeAmount : int)
+ + ticketDidNotWin(details : PlayerDetails)
+ + ticketSubmitError(details : PlayerDetails)
+ + ticketSubmitted(details : PlayerDetails)
+ + ticketWon(details : PlayerDetails, prizeAmount : int)
+ }
+}
+LotteryAdministration --> "-wireTransfers" WireTransfers
+LotteryAdministration --> "-repository" LotteryTicketRepository
+LotteryService --> "-notifications" LotteryEventLog
+MongoEventLog --> "-stdOutEventLog" StdOutEventLog
+LotteryService --> "-wireTransfers" WireTransfers
+LotteryAdministration --> "-notifications" LotteryEventLog
+ConsoleAdministrationSrvImpl --> "-administration" LotteryAdministration
+LotteryService --> "-repository" LotteryTicketRepository
+LotteryTicketCheckResult --> "-result" CheckResult
+ConsoleAdministrationSrvImpl ..|> ConsoleAdministrationSrv
+InMemoryBank ..|> WireTransfers
+MongoBank ..|> WireTransfers
+InMemoryTicketRepository ..|> LotteryTicketRepository
+MongoTicketRepository ..|> LotteryTicketRepository
+MongoEventLog ..|> LotteryEventLog
+StdOutEventLog ..|> LotteryEventLog
+LotteryConsoleServiceImpl ..|> LotteryConsoleService
+@enduml
\ No newline at end of file
diff --git a/marker-interface/etc/marker-interface.urm.puml b/marker-interface/etc/marker-interface.urm.puml
new file mode 100644
index 000000000000..02af47ddf261
--- /dev/null
+++ b/marker-interface/etc/marker-interface.urm.puml
@@ -0,0 +1,2 @@
+@startuml
+@enduml
\ No newline at end of file
diff --git a/microservices-aggregrator/etc/microservices-aggregrator.urm.puml b/microservices-aggregrator/etc/microservices-aggregrator.urm.puml
new file mode 100644
index 000000000000..02af47ddf261
--- /dev/null
+++ b/microservices-aggregrator/etc/microservices-aggregrator.urm.puml
@@ -0,0 +1,2 @@
+@startuml
+@enduml
\ No newline at end of file
diff --git a/microservices-api-gateway/etc/microservices-api-gateway.urm.puml b/microservices-api-gateway/etc/microservices-api-gateway.urm.puml
new file mode 100644
index 000000000000..02af47ddf261
--- /dev/null
+++ b/microservices-api-gateway/etc/microservices-api-gateway.urm.puml
@@ -0,0 +1,2 @@
+@startuml
+@enduml
\ No newline at end of file
diff --git a/microservices-idempotent-consumer/etc/microservices-idempotent-consumer.urm.puml b/microservices-idempotent-consumer/etc/microservices-idempotent-consumer.urm.puml
new file mode 100644
index 000000000000..43fe77181375
--- /dev/null
+++ b/microservices-idempotent-consumer/etc/microservices-idempotent-consumer.urm.puml
@@ -0,0 +1,49 @@
+@startuml
+package com.iluwatar.idempotentconsumer {
+ class App {
+ - LOGGER : Logger {static}
+ + App()
+ + main(args : String[]) {static}
+ + run(requestService : RequestService, requestRepository : RequestRepository) : CommandLineRunner
+ }
+ class Request {
+ - status : Status
+ - uuid : UUID
+ + Request()
+ + Request(uuid : UUID)
+ + Request(uuid : UUID, status : Status)
+ # canEqual(other : Object) : boolean
+ + equals(o : Object) : boolean
+ + getStatus() : Status
+ + getUuid() : UUID
+ + hashCode() : int
+ + setStatus(status : Status)
+ + setUuid(uuid : UUID)
+ + toString() : String
+ }
+ ~enum Status {
+ + COMPLETED {static}
+ + PENDING {static}
+ + STARTED {static}
+ + valueOf(name : String) : Status {static}
+ + values() : Status[] {static}
+ }
+ interface RequestRepository {
+ }
+ class RequestService {
+ ~ requestRepository : RequestRepository
+ ~ requestStateMachine : RequestStateMachine
+ + RequestService(requestRepository : RequestRepository, requestStateMachine : RequestStateMachine)
+ + complete(uuid : UUID) : Request
+ + create(uuid : UUID) : Request
+ + start(uuid : UUID) : Request
+ }
+ class RequestStateMachine {
+ + RequestStateMachine()
+ + next(req : Request, nextStatus : Status) : Request
+ }
+}
+RequestService --> "-requestRepository" RequestRepository
+Request --> "-status" Status
+RequestService --> "-requestStateMachine" RequestStateMachine
+@enduml
\ No newline at end of file
diff --git a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java
index e161b2edc30d..b72f5bffaac5 100644
--- a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java
+++ b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.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.idempotentconsumer;
import org.junit.jupiter.api.Test;
diff --git a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.java b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.java
index af779648c8a3..083cff7ad05e 100644
--- a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.java
+++ b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.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.idempotentconsumer;
import org.junit.jupiter.api.BeforeEach;
diff --git a/microservices-log-aggregation/etc/microservices-log-aggregation.urm.puml b/microservices-log-aggregation/etc/microservices-log-aggregation.urm.puml
new file mode 100644
index 000000000000..1d4551ed025f
--- /dev/null
+++ b/microservices-log-aggregation/etc/microservices-log-aggregation.urm.puml
@@ -0,0 +1,68 @@
+@startuml
+package com.iluwatar.logaggregation {
+ class App {
+ + App()
+ + main(args : String[]) {static}
+ }
+ class CentralLogStore {
+ - LOGGER : Logger {static}
+ - logs : ConcurrentLinkedQueue
+ + CentralLogStore()
+ + displayLogs()
+ + storeLog(logEntry : LogEntry)
+ }
+ class LogAggregator {
+ - BUFFER_THRESHOLD : int {static}
+ - LOGGER : Logger {static}
+ - buffer : ConcurrentLinkedQueue
+ - centralLogStore : CentralLogStore
+ - executorService : ExecutorService
+ - logCount : AtomicInteger
+ - minLogLevel : LogLevel
+ + LogAggregator(centralLogStore : CentralLogStore, minLogLevel : LogLevel)
+ + collectLog(logEntry : LogEntry)
+ - flushBuffer()
+ - startBufferFlusher()
+ + stop()
+ }
+ class LogEntry {
+ - level : LogLevel
+ - message : String
+ - serviceName : String
+ - timestamp : LocalDateTime
+ + LogEntry(serviceName : String, level : LogLevel, message : String, timestamp : LocalDateTime)
+ # canEqual(other : Object) : boolean
+ + equals(o : Object) : boolean
+ + getLevel() : LogLevel
+ + getMessage() : String
+ + getServiceName() : String
+ + getTimestamp() : LocalDateTime
+ + hashCode() : int
+ + setLevel(level : LogLevel)
+ + setMessage(message : String)
+ + setServiceName(serviceName : String)
+ + setTimestamp(timestamp : LocalDateTime)
+ + toString() : String
+ }
+ enum LogLevel {
+ + DEBUG {static}
+ + ERROR {static}
+ + INFO {static}
+ + valueOf(name : String) : LogLevel {static}
+ + values() : LogLevel[] {static}
+ }
+ class LogProducer {
+ - LOGGER : Logger {static}
+ - aggregator : LogAggregator
+ - serviceName : String
+ + LogProducer(serviceName : String, aggregator : LogAggregator)
+ + generateLog(level : LogLevel, message : String)
+ }
+}
+LogAggregator --> "-centralLogStore" CentralLogStore
+LogEntry --> "-level" LogLevel
+CentralLogStore --> "-logs" LogEntry
+LogAggregator --> "-buffer" LogEntry
+LogAggregator --> "-minLogLevel" LogLevel
+LogProducer --> "-aggregator" LogAggregator
+@enduml
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index db06c59a9479..a1478015cd44 100644
--- a/pom.xml
+++ b/pom.xml
@@ -218,6 +218,7 @@
function-composition
microservices-distributed-tracing
microservices-idempotent-consumer
+ Microservice-pattern-Domain-event
diff --git a/queue-based-load-leveling/etc/queue-based-load-leveling.urm.puml b/queue-based-load-leveling/etc/queue-based-load-leveling.urm.puml
new file mode 100644
index 000000000000..ca90842d92dd
--- /dev/null
+++ b/queue-based-load-leveling/etc/queue-based-load-leveling.urm.puml
@@ -0,0 +1,44 @@
+@startuml
+package com.iluwatar.queue.load.leveling {
+ class App {
+ - LOGGER : Logger {static}
+ - SHUTDOWN_TIME : int {static}
+ + App()
+ + main(args : String[]) {static}
+ }
+ class Message {
+ - msg : String
+ + Message(msg : String)
+ + getMsg() : String
+ + toString() : String
+ }
+ class MessageQueue {
+ - LOGGER : Logger {static}
+ - blkQueue : BlockingQueue
+ + MessageQueue()
+ + retrieveMsg() : Message
+ + submitMsg(msg : Message)
+ }
+ class ServiceExecutor {
+ - LOGGER : Logger {static}
+ - msgQueue : MessageQueue
+ + ServiceExecutor(msgQueue : MessageQueue)
+ + run()
+ }
+ interface Task {
+ + submit(Message) {abstract}
+ }
+ class TaskGenerator {
+ - LOGGER : Logger {static}
+ - msgCount : int
+ - msgQueue : MessageQueue
+ + TaskGenerator(msgQueue : MessageQueue, msgCount : int)
+ + run()
+ + submit(msg : Message)
+ }
+}
+MessageQueue --> "-blkQueue" Message
+ServiceExecutor --> "-msgQueue" MessageQueue
+TaskGenerator --> "-msgQueue" MessageQueue
+TaskGenerator ..|> Task
+@enduml
\ No newline at end of file
diff --git a/type-object/src/main/java/com/iluwatar/typeobject/App.java b/type-object/src/main/java/com/iluwatar/typeobject/App.java
index 02058f05fdd2..2fd80a54ee3a 100644
--- a/type-object/src/main/java/com/iluwatar/typeobject/App.java
+++ b/type-object/src/main/java/com/iluwatar/typeobject/App.java
@@ -1,6 +1,5 @@
/*
- * This project is licensed under the MIT license. Module model-view-viewmodel
- * is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ * 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ä
diff --git a/update-header.sh b/update-header.sh
index 48da4dcd6125..568d00d52a03 100755
--- a/update-header.sh
+++ b/update-header.sh
@@ -1,4 +1,29 @@
#!/bin/bash
+#
+# 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.
+#
+
# Find all README.md files in subdirectories one level deep
# and replace "### " with "## " at the beginning of lines
diff --git a/virtual-proxy/etc/virtual-proxy.urm.puml b/virtual-proxy/etc/virtual-proxy.urm.puml
new file mode 100644
index 000000000000..e30149e3809e
--- /dev/null
+++ b/virtual-proxy/etc/virtual-proxy.urm.puml
@@ -0,0 +1,26 @@
+@startuml
+package com.iluwatar.virtual.proxy {
+ class App {
+ + App()
+ + main(args : String[]) {static}
+ }
+ interface ExpensiveObject {
+ + process() {abstract}
+ }
+ class RealVideoObject {
+ - LOGGER : Logger {static}
+ + RealVideoObject()
+ - heavyInitialConfiguration()
+ + process()
+ }
+ class VideoObjectProxy {
+ - realVideoObject : RealVideoObject
+ + VideoObjectProxy()
+ + getRealVideoObject() : RealVideoObject
+ + process()
+ }
+}
+VideoObjectProxy --> "-realVideoObject" RealVideoObject
+RealVideoObject ..|> ExpensiveObject
+VideoObjectProxy ..|> ExpensiveObject
+@enduml
\ No newline at end of file