From ea7503414ef384fe2b09759d58f30cac89f1de26 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Wed, 20 Jul 2016 19:58:20 +0530 Subject: [PATCH 001/492] Work on #403, added basic implementation of promise pattern --- promise/pom.xml | 47 +++++ .../main/java/com/iluwatar/promise/App.java | 24 +++ .../promise/ListenableAsyncResult.java | 12 ++ .../promise/PromiseAsyncExecutor.java | 7 + .../iluwatar/promise/ThreadAsyncExecutor.java | 173 ++++++++++++++++++ 5 files changed, 263 insertions(+) create mode 100644 promise/pom.xml create mode 100644 promise/src/main/java/com/iluwatar/promise/App.java create mode 100644 promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java create mode 100644 promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java create mode 100644 promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java diff --git a/promise/pom.xml b/promise/pom.xml new file mode 100644 index 000000000..ca12515ee --- /dev/null +++ b/promise/pom.xml @@ -0,0 +1,47 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.13.0-SNAPSHOT + + promise + + + junit + junit + test + + + org.mockito + mockito-core + test + + + diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java new file mode 100644 index 000000000..dc22c307a --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -0,0 +1,24 @@ +package com.iluwatar.promise; + +public class App { + + /** + * Program entry point + * @param args arguments + */ + public static void main(String[] args) { + ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); + executor.execute(() -> { + Thread.sleep(1000); + return 10; + }).then(value -> {System.out.println("Consumed the value: " + value);}) + .then(nullVal -> {System.out.println("Post consuming value");}); + + + executor.execute(() -> { + Thread.sleep(1000); + return "10"; + }).then(value -> {return 10 + Integer.parseInt(value);}) + .then(intValue -> {System.out.println("Consumed int value: " + intValue);}); + } +} diff --git a/promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java b/promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java new file mode 100644 index 000000000..a68154e17 --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java @@ -0,0 +1,12 @@ +package com.iluwatar.promise; + +import java.util.function.Consumer; +import java.util.function.Function; + +import com.iluwatar.async.method.invocation.AsyncResult; + +public interface ListenableAsyncResult extends AsyncResult { + ListenableAsyncResult then(Consumer action); + ListenableAsyncResult then(Function func); + ListenableAsyncResult error(Consumer action); +} diff --git a/promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java b/promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java new file mode 100644 index 000000000..eb43b0546 --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java @@ -0,0 +1,7 @@ +package com.iluwatar.promise; + +import java.util.concurrent.Callable; + +public interface PromiseAsyncExecutor { + ListenableAsyncResult execute(Callable task); +} diff --git a/promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java b/promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java new file mode 100644 index 000000000..aa057d676 --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java @@ -0,0 +1,173 @@ +package com.iluwatar.promise; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; + +public class ThreadAsyncExecutor implements PromiseAsyncExecutor { + + /** Index for thread naming */ + private final AtomicInteger idx = new AtomicInteger(0); + + @Override + public ListenableAsyncResult execute(Callable task) { + Promise promise = new Promise<>(); + new Thread(() -> { + try { + promise.setValue(task.call()); + promise.postComplete(); + } catch (Exception ex) { + promise.setException(ex); + } + } , "executor-" + idx.incrementAndGet()).start(); + return promise; + } + + // TODO there is scope of extending the completable future from async method invocation project. Do that. + private class Promise implements ListenableAsyncResult { + + static final int RUNNING = 1; + static final int FAILED = 2; + static final int COMPLETED = 3; + + final Object lock; + volatile int state = RUNNING; + T value; + Exception exception; + Runnable fulfilmentAction; + + public Promise() { + this.lock = new Object(); + } + + void postComplete() { + fulfilmentAction.run(); + } + + /** + * Sets the value from successful execution and executes callback if available. Notifies any thread waiting for + * completion. + * + * @param value + * value of the evaluated task + */ + public void setValue(T value) { + this.value = value; + this.state = COMPLETED; + synchronized (lock) { + lock.notifyAll(); + } + } + + /** + * Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for + * completion. + * + * @param exception + * exception of the failed task + */ + public void setException(Exception exception) { + this.exception = exception; + this.state = FAILED; + synchronized (lock) { + lock.notifyAll(); + } + } + + @Override + public boolean isCompleted() { + return state > RUNNING; + } + + @Override + public T getValue() throws ExecutionException { + if (state == COMPLETED) { + return value; + } else if (state == FAILED) { + throw new ExecutionException(exception); + } else { + throw new IllegalStateException("Execution not completed yet"); + } + } + + @Override + public void await() throws InterruptedException { + synchronized (lock) { + if (!isCompleted()) { + lock.wait(); + } + } + } + + @Override + public ListenableAsyncResult then(Consumer action) { + Promise dest = new Promise<>(); + fulfilmentAction = new ConsumeAction(this, dest, action); + return dest; + } + + @Override + public ListenableAsyncResult then(Function func) { + Promise dest = new Promise<>(); + fulfilmentAction = new FunctionAction(this, dest, func); + return dest; + } + + @Override + public ListenableAsyncResult error(Consumer action) { + return null; + } + + private class ConsumeAction implements Runnable { + + private Promise current; + private Promise dest; + private Consumer action; + + public ConsumeAction(Promise current, Promise dest, Consumer action) { + this.current = current; + this.dest = dest; + this.action = action; + } + + @Override + public void run() { + try { + action.accept(current.getValue()); + dest.setValue(null); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + dest.postComplete(); + } + } + + private class FunctionAction implements Runnable { + + private Promise current; + private Promise dest; + private Function func; + + public FunctionAction(Promise current, Promise dest, Function func) { + this.current = current; + this.dest = dest; + this.func = func; + } + + @Override + public void run() { + try { + V result = func.apply(current.getValue()); + dest.setValue(result); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + dest.postComplete(); + } + } + } + } \ No newline at end of file From 102341443d33b7cca89f4e37b7c2e490fe780584 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Thu, 21 Jul 2016 19:13:42 +0530 Subject: [PATCH 002/492] Work on #403, added application class and test cases. --- pom.xml | 1 + promise/pom.xml | 5 + .../main/java/com/iluwatar/promise/App.java | 30 ++- .../promise/ListenableAsyncResult.java | 12 -- .../java/com/iluwatar/promise/Promise.java | 143 +++++++++++++++ .../promise/PromiseAsyncExecutor.java | 7 - .../iluwatar/promise/ThreadAsyncExecutor.java | 173 ------------------ .../java/com/iluwatar/promise/AppTest.java | 15 ++ .../com/iluwatar/promise/PromiseTest.java | 128 +++++++++++++ 9 files changed, 314 insertions(+), 200 deletions(-) delete mode 100644 promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java create mode 100644 promise/src/main/java/com/iluwatar/promise/Promise.java delete mode 100644 promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java delete mode 100644 promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java create mode 100644 promise/src/test/java/com/iluwatar/promise/AppTest.java create mode 100644 promise/src/test/java/com/iluwatar/promise/PromiseTest.java diff --git a/pom.xml b/pom.xml index 6f3e0d698..45d574e73 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,7 @@ hexagonal abstract-document aggregator-microservices + promise page-object diff --git a/promise/pom.xml b/promise/pom.xml index ca12515ee..f5727b951 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -43,5 +43,10 @@ mockito-core test + + com.iluwatar + async-method-invocation + 1.13.0-SNAPSHOT + diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index dc22c307a..5817e68da 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -1,24 +1,38 @@ package com.iluwatar.promise; +import com.iluwatar.async.method.invocation.ThreadAsyncExecutor; + +/** + * + * Application that uses promise pattern. + */ public class App { /** * Program entry point * @param args arguments + * @throws InterruptedException if main thread is interruped. */ - public static void main(String[] args) { + public static void main(String[] args) throws InterruptedException { ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); - executor.execute(() -> { + + Promise consumedPromise = new Promise<>(); + consumedPromise.fulfillInAsync(() -> { Thread.sleep(1000); return 10; - }).then(value -> {System.out.println("Consumed the value: " + value);}) - .then(nullVal -> {System.out.println("Post consuming value");}); + }, executor).then(value -> { + System.out.println("Consumed int value: " + value); + }); - - executor.execute(() -> { + Promise transformedPromise = new Promise<>(); + transformedPromise.fulfillInAsync(() -> { Thread.sleep(1000); return "10"; - }).then(value -> {return 10 + Integer.parseInt(value);}) - .then(intValue -> {System.out.println("Consumed int value: " + intValue);}); + }, executor).then(value -> { return Integer.parseInt(value); }).then(value -> { + System.out.println(value); + }); + + consumedPromise.await(); + transformedPromise.await(); } } diff --git a/promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java b/promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java deleted file mode 100644 index a68154e17..000000000 --- a/promise/src/main/java/com/iluwatar/promise/ListenableAsyncResult.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.iluwatar.promise; - -import java.util.function.Consumer; -import java.util.function.Function; - -import com.iluwatar.async.method.invocation.AsyncResult; - -public interface ListenableAsyncResult extends AsyncResult { - ListenableAsyncResult then(Consumer action); - ListenableAsyncResult then(Function func); - ListenableAsyncResult error(Consumer action); -} diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java new file mode 100644 index 000000000..0bc4accbb --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -0,0 +1,143 @@ +package com.iluwatar.promise; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; +import java.util.function.Function; + +import com.iluwatar.async.method.invocation.AsyncExecutor; +import com.iluwatar.async.method.invocation.internal.CompletableResult; + +/** + * Implements the promise pattern. + * @param type of result. + */ +public class Promise extends CompletableResult { + + private Runnable fulfillmentAction; + + /** + * Creates a promise that will be fulfilled in future. + */ + public Promise() { + super(null); + } + + /** + * Fulfills the promise with the provided value. + * @param value the fulfilled value that can be accessed using {@link #getValue()}. + */ + @Override + public void setValue(T value) { + super.setValue(value); + postComplete(); + } + + /** + * Fulfills the promise with exception due to error in execution. + * @param exception the exception will be wrapped in {@link ExecutionException} + * when accessing the value using {@link #getValue()}. + */ + @Override + public void setException(Exception exception) { + super.setException(exception); + postComplete(); + } + + void postComplete() { + if (fulfillmentAction == null) { + return; + } + fulfillmentAction.run(); + } + + /** + * Executes the task using the executor in other thread and fulfills the promise returned + * once the task completes either successfully or with an exception. + * + * @param task the task that will provide the value to fulfill the promise. + * @param executor the executor in which the task should be run. + * @return a promise that represents the result of running the task provided. + */ + public Promise fulfillInAsync(final Callable task, AsyncExecutor executor) { + executor.startProcess(new Callable() { + + @Override + public Void call() throws Exception { + setValue(task.call()); + return null; + } + }); + return this; + } + + /** + * Returns a new promise that, when this promise is fulfilled normally, is fulfilled with + * result of this promise as argument to the action provided. + * @param action action to be executed. + * @return a new promise. + */ + public Promise then(Consumer action) { + Promise dest = new Promise<>(); + fulfillmentAction = new ConsumeAction(this, dest, action); + return dest; + } + + /** + * Returns a new promise that, when this promise is fulfilled normally, is fulfilled with + * result of this promise as argument to the function provided. + * @param func function to be executed. + * @return a new promise. + */ + public Promise then(Function func) { + Promise dest = new Promise<>(); + fulfillmentAction = new FunctionAction(this, dest, func); + return dest; + } + + private class ConsumeAction implements Runnable { + + private Promise current; + private Promise dest; + private Consumer action; + + public ConsumeAction(Promise current, Promise dest, Consumer action) { + this.current = current; + this.dest = dest; + this.action = action; + } + + @Override + public void run() { + try { + action.accept(current.getValue()); + dest.setValue(null); + } catch (Throwable e) { + dest.setException((Exception) e.getCause()); + } + } + } + + private class FunctionAction implements Runnable { + + private Promise current; + private Promise dest; + private Function func; + + public FunctionAction(Promise current, Promise dest, Function func) { + this.current = current; + this.dest = dest; + this.func = func; + } + + @Override + public void run() { + try { + V result = func.apply(current.getValue()); + dest.setValue(result); + } catch (Throwable e) { + dest.setException((Exception) e.getCause()); + } + } + } +} diff --git a/promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java b/promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java deleted file mode 100644 index eb43b0546..000000000 --- a/promise/src/main/java/com/iluwatar/promise/PromiseAsyncExecutor.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.iluwatar.promise; - -import java.util.concurrent.Callable; - -public interface PromiseAsyncExecutor { - ListenableAsyncResult execute(Callable task); -} diff --git a/promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java b/promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java deleted file mode 100644 index aa057d676..000000000 --- a/promise/src/main/java/com/iluwatar/promise/ThreadAsyncExecutor.java +++ /dev/null @@ -1,173 +0,0 @@ -package com.iluwatar.promise; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.function.Function; - -public class ThreadAsyncExecutor implements PromiseAsyncExecutor { - - /** Index for thread naming */ - private final AtomicInteger idx = new AtomicInteger(0); - - @Override - public ListenableAsyncResult execute(Callable task) { - Promise promise = new Promise<>(); - new Thread(() -> { - try { - promise.setValue(task.call()); - promise.postComplete(); - } catch (Exception ex) { - promise.setException(ex); - } - } , "executor-" + idx.incrementAndGet()).start(); - return promise; - } - - // TODO there is scope of extending the completable future from async method invocation project. Do that. - private class Promise implements ListenableAsyncResult { - - static final int RUNNING = 1; - static final int FAILED = 2; - static final int COMPLETED = 3; - - final Object lock; - volatile int state = RUNNING; - T value; - Exception exception; - Runnable fulfilmentAction; - - public Promise() { - this.lock = new Object(); - } - - void postComplete() { - fulfilmentAction.run(); - } - - /** - * Sets the value from successful execution and executes callback if available. Notifies any thread waiting for - * completion. - * - * @param value - * value of the evaluated task - */ - public void setValue(T value) { - this.value = value; - this.state = COMPLETED; - synchronized (lock) { - lock.notifyAll(); - } - } - - /** - * Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for - * completion. - * - * @param exception - * exception of the failed task - */ - public void setException(Exception exception) { - this.exception = exception; - this.state = FAILED; - synchronized (lock) { - lock.notifyAll(); - } - } - - @Override - public boolean isCompleted() { - return state > RUNNING; - } - - @Override - public T getValue() throws ExecutionException { - if (state == COMPLETED) { - return value; - } else if (state == FAILED) { - throw new ExecutionException(exception); - } else { - throw new IllegalStateException("Execution not completed yet"); - } - } - - @Override - public void await() throws InterruptedException { - synchronized (lock) { - if (!isCompleted()) { - lock.wait(); - } - } - } - - @Override - public ListenableAsyncResult then(Consumer action) { - Promise dest = new Promise<>(); - fulfilmentAction = new ConsumeAction(this, dest, action); - return dest; - } - - @Override - public ListenableAsyncResult then(Function func) { - Promise dest = new Promise<>(); - fulfilmentAction = new FunctionAction(this, dest, func); - return dest; - } - - @Override - public ListenableAsyncResult error(Consumer action) { - return null; - } - - private class ConsumeAction implements Runnable { - - private Promise current; - private Promise dest; - private Consumer action; - - public ConsumeAction(Promise current, Promise dest, Consumer action) { - this.current = current; - this.dest = dest; - this.action = action; - } - - @Override - public void run() { - try { - action.accept(current.getValue()); - dest.setValue(null); - } catch (ExecutionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - dest.postComplete(); - } - } - - private class FunctionAction implements Runnable { - - private Promise current; - private Promise dest; - private Function func; - - public FunctionAction(Promise current, Promise dest, Function func) { - this.current = current; - this.dest = dest; - this.func = func; - } - - @Override - public void run() { - try { - V result = func.apply(current.getValue()); - dest.setValue(result); - } catch (ExecutionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - dest.postComplete(); - } - } - } - } \ No newline at end of file diff --git a/promise/src/test/java/com/iluwatar/promise/AppTest.java b/promise/src/test/java/com/iluwatar/promise/AppTest.java new file mode 100644 index 000000000..b59187cb1 --- /dev/null +++ b/promise/src/test/java/com/iluwatar/promise/AppTest.java @@ -0,0 +1,15 @@ +package com.iluwatar.promise; + +import org.junit.Test; + +/** + * + * Application test. + */ +public class AppTest { + + @Test + public void testApp() throws InterruptedException { + App.main(null); + } +} diff --git a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java new file mode 100644 index 000000000..9c28be1b3 --- /dev/null +++ b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java @@ -0,0 +1,128 @@ +package com.iluwatar.promise; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.iluwatar.async.method.invocation.ThreadAsyncExecutor; + +/** + * Tests Promise class. + */ +public class PromiseTest { + + private ThreadAsyncExecutor executor; + private Promise promise; + @Rule public ExpectedException exception = ExpectedException.none(); + + @Before + public void setUp() { + executor = new ThreadAsyncExecutor(); + promise = new Promise<>(); + } + + @Test + public void promiseIsFulfilledWithTheResultantValueOfExecutingTheTask() + throws InterruptedException, ExecutionException { + promise.fulfillInAsync(new NumberCrunchingTask(), executor); + + // await fulfillment + promise.await(); + + assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, promise.getValue()); + } + + @Test + public void dependentPromiseIsFulfilledAfterTheConsumerConsumesTheResultOfThisPromise() + throws InterruptedException, ExecutionException { + Promise dependentPromise = promise + .fulfillInAsync(new NumberCrunchingTask(), executor) + .then(value -> { + assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value); + }); + + + // await fulfillment + dependentPromise.await(); + } + + @Test + public void dependentPromiseIsFulfilledWithAnExceptionIfConsumerThrowsAnException() + throws InterruptedException, ExecutionException { + Promise dependentPromise = promise + .fulfillInAsync(new NumberCrunchingTask(), executor) + .then(new Consumer() { + + @Override + public void accept(Integer t) { + throw new RuntimeException("Barf!"); + } + }); + + + // await fulfillment + dependentPromise.await(); + + exception.expect(ExecutionException.class); + + dependentPromise.getValue(); + } + + @Test + public void dependentPromiseIsFulfilledAfterTheFunctionTransformsTheResultOfThisPromise() + throws InterruptedException, ExecutionException { + Promise dependentPromise = promise + .fulfillInAsync(new NumberCrunchingTask(), executor) + .then(value -> { + assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value); + return String.valueOf(value); + }); + + + // await fulfillment + dependentPromise.await(); + + assertEquals(String.valueOf(NumberCrunchingTask.CRUNCHED_NUMBER), dependentPromise.getValue()); + } + + @Test + public void dependentPromiseIsFulfilledWithAnExceptionIfTheFunctionThrowsException() + throws InterruptedException, ExecutionException { + Promise dependentPromise = promise + .fulfillInAsync(new NumberCrunchingTask(), executor) + .then(new Function() { + + @Override + public String apply(Integer t) { + throw new RuntimeException("Barf!"); + } + }); + + // await fulfillment + dependentPromise.await(); + + exception.expect(ExecutionException.class); + + dependentPromise.getValue(); + } + + private static class NumberCrunchingTask implements Callable { + + private static final Integer CRUNCHED_NUMBER = Integer.MAX_VALUE; + + @Override + public Integer call() throws Exception { + // Do number crunching + Thread.sleep(1000); + return CRUNCHED_NUMBER; + } + } +} From 2b945ca27f991d03a5ffd58d4faa809d1aa8df23 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Fri, 22 Jul 2016 16:47:52 +0530 Subject: [PATCH 003/492] Work on #403, removed dependency on async method invocation module, added more tests --- promise/pom.xml | 5 - .../main/java/com/iluwatar/promise/App.java | 26 ++- .../java/com/iluwatar/promise/Promise.java | 169 ++++++++++++++---- .../java/com/iluwatar/promise/AppTest.java | 4 +- .../com/iluwatar/promise/PromiseTest.java | 147 ++++++++++++--- 5 files changed, 275 insertions(+), 76 deletions(-) diff --git a/promise/pom.xml b/promise/pom.xml index f5727b951..ca12515ee 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -43,10 +43,5 @@ mockito-core test - - com.iluwatar - async-method-invocation - 1.13.0-SNAPSHOT - diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 5817e68da..f9e089f3d 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -1,6 +1,9 @@ package com.iluwatar.promise; -import com.iluwatar.async.method.invocation.ThreadAsyncExecutor; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * @@ -12,10 +15,19 @@ public class App { * Program entry point * @param args arguments * @throws InterruptedException if main thread is interruped. + * @throws ExecutionException */ - public static void main(String[] args) throws InterruptedException { - ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); - + public static void main(String[] args) throws InterruptedException, ExecutionException { + ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + promiseUsage(executor); + } finally { + executor.shutdownNow(); + } + } + + private static void promiseUsage(Executor executor) + throws InterruptedException, ExecutionException { Promise consumedPromise = new Promise<>(); consumedPromise.fulfillInAsync(() -> { Thread.sleep(1000); @@ -29,10 +41,10 @@ public class App { Thread.sleep(1000); return "10"; }, executor).then(value -> { return Integer.parseInt(value); }).then(value -> { - System.out.println(value); + System.out.println("Consumed transformed int value: " + value); }); - consumedPromise.await(); - transformedPromise.await(); + consumedPromise.get(); + transformedPromise.get(); } } diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index 0bc4accbb..991c2a05c 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -2,17 +2,18 @@ package com.iluwatar.promise; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import java.util.function.Function; -import com.iluwatar.async.method.invocation.AsyncExecutor; -import com.iluwatar.async.method.invocation.internal.CompletableResult; - /** * Implements the promise pattern. * @param type of result. */ -public class Promise extends CompletableResult { +public class Promise extends PromiseSupport { private Runnable fulfillmentAction; @@ -20,31 +21,30 @@ public class Promise extends CompletableResult { * Creates a promise that will be fulfilled in future. */ public Promise() { - super(null); } /** * Fulfills the promise with the provided value. - * @param value the fulfilled value that can be accessed using {@link #getValue()}. + * @param value the fulfilled value that can be accessed using {@link #get()}. */ @Override - public void setValue(T value) { - super.setValue(value); - postComplete(); + public void fulfill(T value) { + super.fulfill(value); + postFulfillment(); } /** * Fulfills the promise with exception due to error in execution. * @param exception the exception will be wrapped in {@link ExecutionException} - * when accessing the value using {@link #getValue()}. + * when accessing the value using {@link #get()}. */ @Override - public void setException(Exception exception) { - super.setException(exception); - postComplete(); + public void fulfillExceptionally(Exception exception) { + super.fulfillExceptionally(exception); + postFulfillment(); } - void postComplete() { + void postFulfillment() { if (fulfillmentAction == null) { return; } @@ -59,13 +59,12 @@ public class Promise extends CompletableResult { * @param executor the executor in which the task should be run. * @return a promise that represents the result of running the task provided. */ - public Promise fulfillInAsync(final Callable task, AsyncExecutor executor) { - executor.startProcess(new Callable() { - - @Override - public Void call() throws Exception { - setValue(task.call()); - return null; + public Promise fulfillInAsync(final Callable task, Executor executor) { + executor.execute(() -> { + try { + fulfill(task.call()); + } catch (Exception e) { + fulfillExceptionally(e); } }); return this; @@ -91,18 +90,22 @@ public class Promise extends CompletableResult { */ public Promise then(Function func) { Promise dest = new Promise<>(); - fulfillmentAction = new FunctionAction(this, dest, func); + fulfillmentAction = new TransformAction(this, dest, func); return dest; } + /** + * A consume action provides the action, the value from source promise and fulfills the + * destination promise. + */ private class ConsumeAction implements Runnable { - private Promise current; + private Promise src; private Promise dest; private Consumer action; - public ConsumeAction(Promise current, Promise dest, Consumer action) { - this.current = current; + ConsumeAction(Promise src, Promise dest, Consumer action) { + this.src = src; this.dest = dest; this.action = action; } @@ -110,22 +113,26 @@ public class Promise extends CompletableResult { @Override public void run() { try { - action.accept(current.getValue()); - dest.setValue(null); + action.accept(src.get()); + dest.fulfill(null); } catch (Throwable e) { - dest.setException((Exception) e.getCause()); + dest.fulfillExceptionally((Exception) e.getCause()); } } } - private class FunctionAction implements Runnable { + /** + * A function action provides transformation function, value from source promise and fulfills the + * destination promise with the transformed value. + */ + private class TransformAction implements Runnable { - private Promise current; + private Promise src; private Promise dest; private Function func; - public FunctionAction(Promise current, Promise dest, Function func) { - this.current = current; + TransformAction(Promise src, Promise dest, Function func) { + this.src = src; this.dest = dest; this.func = func; } @@ -133,11 +140,103 @@ public class Promise extends CompletableResult { @Override public void run() { try { - V result = func.apply(current.getValue()); - dest.setValue(result); + V result = func.apply(src.get()); + dest.fulfill(result); } catch (Throwable e) { - dest.setException((Exception) e.getCause()); + dest.fulfillExceptionally((Exception) e.getCause()); } } } } + + +/** + * A really simplified implementation of future that allows completing it successfully with a value + * or exceptionally with an exception. + */ +class PromiseSupport implements Future { + + static final int RUNNING = 1; + static final int FAILED = 2; + static final int COMPLETED = 3; + + final Object lock; + + volatile int state = RUNNING; + T value; + Exception exception; + + PromiseSupport() { + this.lock = new Object(); + } + + void fulfill(T value) { + this.value = value; + this.state = COMPLETED; + synchronized (lock) { + lock.notifyAll(); + } + } + + void fulfillExceptionally(Exception exception) { + this.exception = exception; + this.state = FAILED; + synchronized (lock) { + lock.notifyAll(); + } + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return state > RUNNING; + } + + @Override + public T get() throws InterruptedException, ExecutionException { + if (state == COMPLETED) { + return value; + } else if (state == FAILED) { + throw new ExecutionException(exception); + } else { + synchronized (lock) { + lock.wait(); + if (state == COMPLETED) { + return value; + } else { + throw new ExecutionException(exception); + } + } + } + } + + @Override + public T get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + if (state == COMPLETED) { + return value; + } else if (state == FAILED) { + throw new ExecutionException(exception); + } else { + synchronized (lock) { + lock.wait(unit.toMillis(timeout)); + if (state == COMPLETED) { + return value; + } else if (state == FAILED) { + throw new ExecutionException(exception); + } else { + throw new TimeoutException(); + } + } + } + } +} \ No newline at end of file diff --git a/promise/src/test/java/com/iluwatar/promise/AppTest.java b/promise/src/test/java/com/iluwatar/promise/AppTest.java index b59187cb1..b2628127c 100644 --- a/promise/src/test/java/com/iluwatar/promise/AppTest.java +++ b/promise/src/test/java/com/iluwatar/promise/AppTest.java @@ -1,5 +1,7 @@ package com.iluwatar.promise; +import java.util.concurrent.ExecutionException; + import org.junit.Test; /** @@ -9,7 +11,7 @@ import org.junit.Test; public class AppTest { @Test - public void testApp() throws InterruptedException { + public void testApp() throws InterruptedException, ExecutionException { App.main(null); } } diff --git a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java index 9c28be1b3..c64b82d06 100644 --- a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java +++ b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java @@ -1,9 +1,16 @@ package com.iluwatar.promise; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import java.util.function.Function; @@ -12,20 +19,18 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import com.iluwatar.async.method.invocation.ThreadAsyncExecutor; - /** * Tests Promise class. */ public class PromiseTest { - private ThreadAsyncExecutor executor; + private Executor executor; private Promise promise; @Rule public ExpectedException exception = ExpectedException.none(); @Before public void setUp() { - executor = new ThreadAsyncExecutor(); + executor = Executors.newSingleThreadExecutor(); promise = new Promise<>(); } @@ -34,10 +39,70 @@ public class PromiseTest { throws InterruptedException, ExecutionException { promise.fulfillInAsync(new NumberCrunchingTask(), executor); - // await fulfillment - promise.await(); + assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, promise.get()); + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + + @Test + public void promiseIsFulfilledWithAnExceptionIfTaskThrowsAnException() + throws InterruptedException, ExecutionException, TimeoutException { + testWaitingForeverForPromiseToBeFulfilled(); + testWaitingSomeTimeForPromiseToBeFulfilled(); + } - assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, promise.getValue()); + private void testWaitingForeverForPromiseToBeFulfilled() throws InterruptedException, TimeoutException { + Promise promise = new Promise<>(); + promise.fulfillInAsync(new Callable() { + + @Override + public Integer call() throws Exception { + throw new RuntimeException("Barf!"); + }}, executor); + + try { + promise.get(); + fail("Fetching promise should result in exception if the task threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + + try { + promise.get(1000, TimeUnit.SECONDS); + fail("Fetching promise should result in exception if the task threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + } + + private void testWaitingSomeTimeForPromiseToBeFulfilled() + throws InterruptedException, TimeoutException { + Promise promise = new Promise<>(); + promise.fulfillInAsync(new Callable() { + + @Override + public Integer call() throws Exception { + throw new RuntimeException("Barf!"); + }}, executor); + + try { + promise.get(1000, TimeUnit.SECONDS); + fail("Fetching promise should result in exception if the task threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + + try { + promise.get(); + fail("Fetching promise should result in exception if the task threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + } @Test @@ -50,13 +115,14 @@ public class PromiseTest { }); - // await fulfillment - dependentPromise.await(); + dependentPromise.get(); + assertTrue(dependentPromise.isDone()); + assertFalse(dependentPromise.isCancelled()); } @Test public void dependentPromiseIsFulfilledWithAnExceptionIfConsumerThrowsAnException() - throws InterruptedException, ExecutionException { + throws InterruptedException, ExecutionException, TimeoutException { Promise dependentPromise = promise .fulfillInAsync(new NumberCrunchingTask(), executor) .then(new Consumer() { @@ -67,13 +133,21 @@ public class PromiseTest { } }); - - // await fulfillment - dependentPromise.await(); - - exception.expect(ExecutionException.class); - - dependentPromise.getValue(); + try { + dependentPromise.get(); + fail("Fetching dependent promise should result in exception if the action threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + + try { + dependentPromise.get(1000, TimeUnit.SECONDS); + fail("Fetching dependent promise should result in exception if the action threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } } @Test @@ -87,15 +161,14 @@ public class PromiseTest { }); - // await fulfillment - dependentPromise.await(); - - assertEquals(String.valueOf(NumberCrunchingTask.CRUNCHED_NUMBER), dependentPromise.getValue()); + assertEquals(String.valueOf(NumberCrunchingTask.CRUNCHED_NUMBER), dependentPromise.get()); + assertTrue(dependentPromise.isDone()); + assertFalse(dependentPromise.isCancelled()); } @Test public void dependentPromiseIsFulfilledWithAnExceptionIfTheFunctionThrowsException() - throws InterruptedException, ExecutionException { + throws InterruptedException, ExecutionException, TimeoutException { Promise dependentPromise = promise .fulfillInAsync(new NumberCrunchingTask(), executor) .then(new Function() { @@ -106,12 +179,30 @@ public class PromiseTest { } }); - // await fulfillment - dependentPromise.await(); - - exception.expect(ExecutionException.class); - - dependentPromise.getValue(); + try { + dependentPromise.get(); + fail("Fetching dependent promise should result in exception if the function threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + + try { + dependentPromise.get(1000, TimeUnit.SECONDS); + fail("Fetching dependent promise should result in exception if the function threw an exception"); + } catch (ExecutionException ex) { + assertTrue(promise.isDone()); + assertFalse(promise.isCancelled()); + } + } + + @Test + public void fetchingAnAlreadyFulfilledPromiseReturnsTheFulfilledValueImmediately() + throws InterruptedException, ExecutionException, TimeoutException { + Promise promise = new Promise<>(); + promise.fulfill(NumberCrunchingTask.CRUNCHED_NUMBER); + + promise.get(1000, TimeUnit.SECONDS); } private static class NumberCrunchingTask implements Callable { From eb560f5f54b6a928e978b81549d7369f957364a0 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Fri, 22 Jul 2016 16:53:01 +0530 Subject: [PATCH 004/492] Work on #403, removed checkstyle violations --- .../main/java/com/iluwatar/promise/App.java | 2 +- .../java/com/iluwatar/promise/Promise.java | 95 ------------------- .../com/iluwatar/promise/PromiseTest.java | 6 +- 3 files changed, 5 insertions(+), 98 deletions(-) diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index f9e089f3d..3390f2a23 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -15,7 +15,7 @@ public class App { * Program entry point * @param args arguments * @throws InterruptedException if main thread is interruped. - * @throws ExecutionException + * @throws ExecutionException if an execution error occurs. */ public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executor = Executors.newSingleThreadExecutor(); diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index 991c2a05c..03977c541 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -3,9 +3,6 @@ package com.iluwatar.promise; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import java.util.function.Function; @@ -147,96 +144,4 @@ public class Promise extends PromiseSupport { } } } -} - - -/** - * A really simplified implementation of future that allows completing it successfully with a value - * or exceptionally with an exception. - */ -class PromiseSupport implements Future { - - static final int RUNNING = 1; - static final int FAILED = 2; - static final int COMPLETED = 3; - - final Object lock; - - volatile int state = RUNNING; - T value; - Exception exception; - - PromiseSupport() { - this.lock = new Object(); - } - - void fulfill(T value) { - this.value = value; - this.state = COMPLETED; - synchronized (lock) { - lock.notifyAll(); - } - } - - void fulfillExceptionally(Exception exception) { - this.exception = exception; - this.state = FAILED; - synchronized (lock) { - lock.notifyAll(); - } - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return state > RUNNING; - } - - @Override - public T get() throws InterruptedException, ExecutionException { - if (state == COMPLETED) { - return value; - } else if (state == FAILED) { - throw new ExecutionException(exception); - } else { - synchronized (lock) { - lock.wait(); - if (state == COMPLETED) { - return value; - } else { - throw new ExecutionException(exception); - } - } - } - } - - @Override - public T get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - if (state == COMPLETED) { - return value; - } else if (state == FAILED) { - throw new ExecutionException(exception); - } else { - synchronized (lock) { - lock.wait(unit.toMillis(timeout)); - if (state == COMPLETED) { - return value; - } else if (state == FAILED) { - throw new ExecutionException(exception); - } else { - throw new TimeoutException(); - } - } - } - } } \ No newline at end of file diff --git a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java index c64b82d06..842558589 100644 --- a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java +++ b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java @@ -58,7 +58,8 @@ public class PromiseTest { @Override public Integer call() throws Exception { throw new RuntimeException("Barf!"); - }}, executor); + } + }, executor); try { promise.get(); @@ -85,7 +86,8 @@ public class PromiseTest { @Override public Integer call() throws Exception { throw new RuntimeException("Barf!"); - }}, executor); + } + }, executor); try { promise.get(1000, TimeUnit.SECONDS); From 09ba5ca656dd17ac5c2d518452ad5f89df388e57 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Fri, 22 Jul 2016 18:34:05 +0530 Subject: [PATCH 005/492] Work on #403, added class diagrams and javadocs --- promise/etc/promise.png | Bin 0 -> 59544 bytes promise/etc/promise.ucls | 115 +++++++++++++++++ .../main/java/com/iluwatar/promise/App.java | 44 ++++++- .../java/com/iluwatar/promise/Promise.java | 25 +++- .../com/iluwatar/promise/PromiseSupport.java | 119 ++++++++++++++++++ .../java/com/iluwatar/promise/AppTest.java | 22 ++++ .../com/iluwatar/promise/PromiseTest.java | 22 ++++ 7 files changed, 344 insertions(+), 3 deletions(-) create mode 100644 promise/etc/promise.png create mode 100644 promise/etc/promise.ucls create mode 100644 promise/src/main/java/com/iluwatar/promise/PromiseSupport.java diff --git a/promise/etc/promise.png b/promise/etc/promise.png new file mode 100644 index 0000000000000000000000000000000000000000..1a0f671080915d26268f2ce16df59c430a14926e GIT binary patch literal 59544 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 literal 0 HcmV?d00001 diff --git a/promise/etc/promise.ucls b/promise/etc/promise.ucls new file mode 100644 index 000000000..fe3c6c2e0 --- /dev/null +++ b/promise/etc/promise.ucls @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 3390f2a23..6ce7de994 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -1,5 +1,28 @@ +/** + * The MIT License + * Copyright (c) 2014 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.promise; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -7,14 +30,31 @@ import java.util.concurrent.Executors; /** * - * Application that uses promise pattern. + *

The Promise object is used for asynchronous computations. A Promise represents an operation that + * hasn't completed yet, but is expected in the future. + * + *

A Promise represents a proxy for a value not necessarily known when the promise is created. It + * allows you to associate dependent promises to an asynchronous action's eventual success value or + * failure reason. This lets asynchronous methods return values like synchronous methods: instead of the final + * value, the asynchronous method returns a promise of having a value at some point in the future. + * + *

Promises provide a few advantages over callback objects: + *

    + *
  • Functional composition and error handling + *
  • Prevents callback hell and provides callback aggregation + *
+ * + * @see CompletableFuture */ public class App { + private App() { + } + /** * Program entry point * @param args arguments - * @throws InterruptedException if main thread is interruped. + * @throws InterruptedException if main thread is interrupted. * @throws ExecutionException if an execution error occurs. */ public static void main(String[] args) throws InterruptedException, ExecutionException { diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index 03977c541..fe7dc6f9f 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.promise; import java.util.concurrent.Callable; @@ -8,6 +30,7 @@ import java.util.function.Function; /** * Implements the promise pattern. + * * @param type of result. */ public class Promise extends PromiseSupport { @@ -41,7 +64,7 @@ public class Promise extends PromiseSupport { postFulfillment(); } - void postFulfillment() { + private void postFulfillment() { if (fulfillmentAction == null) { return; } diff --git a/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java new file mode 100644 index 000000000..dde2ca452 --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java @@ -0,0 +1,119 @@ +/** + * The MIT License + * Copyright (c) 2014 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.promise; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * A really simplified implementation of future that allows completing it successfully with a value + * or exceptionally with an exception. + */ +class PromiseSupport implements Future { + + static final int RUNNING = 1; + static final int FAILED = 2; + static final int COMPLETED = 3; + + final Object lock; + + volatile int state = RUNNING; + T value; + Exception exception; + + PromiseSupport() { + this.lock = new Object(); + } + + void fulfill(T value) { + this.value = value; + this.state = COMPLETED; + synchronized (lock) { + lock.notifyAll(); + } + } + + void fulfillExceptionally(Exception exception) { + this.exception = exception; + this.state = FAILED; + synchronized (lock) { + lock.notifyAll(); + } + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return state > RUNNING; + } + + @Override + public T get() throws InterruptedException, ExecutionException { + if (state == COMPLETED) { + return value; + } else if (state == FAILED) { + throw new ExecutionException(exception); + } else { + synchronized (lock) { + lock.wait(); + if (state == COMPLETED) { + return value; + } else { + throw new ExecutionException(exception); + } + } + } + } + + @Override + public T get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + if (state == COMPLETED) { + return value; + } else if (state == FAILED) { + throw new ExecutionException(exception); + } else { + synchronized (lock) { + lock.wait(unit.toMillis(timeout)); + if (state == COMPLETED) { + return value; + } else if (state == FAILED) { + throw new ExecutionException(exception); + } else { + throw new TimeoutException(); + } + } + } + } +} \ No newline at end of file diff --git a/promise/src/test/java/com/iluwatar/promise/AppTest.java b/promise/src/test/java/com/iluwatar/promise/AppTest.java index b2628127c..1d1cb061d 100644 --- a/promise/src/test/java/com/iluwatar/promise/AppTest.java +++ b/promise/src/test/java/com/iluwatar/promise/AppTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.promise; import java.util.concurrent.ExecutionException; diff --git a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java index 842558589..de0ecb6d7 100644 --- a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java +++ b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.promise; import static org.junit.Assert.assertEquals; From 40ac5525421fa2932224048fce76aded3fe3f332 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sun, 24 Jul 2016 01:45:49 +0530 Subject: [PATCH 006/492] Work on #403, added README --- promise/README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 promise/README.md diff --git a/promise/README.md b/promise/README.md new file mode 100644 index 000000000..069a8dbfe --- /dev/null +++ b/promise/README.md @@ -0,0 +1,45 @@ +--- +layout: pattern +title: Promise +folder: promise +permalink: /patterns/promise/ +categories: Structural +tags: + - Java + - Concurrency + - Difficulty-Intermediate +--- + +## Also known as +CompletableFuture + +## Intent +A Promise represents a proxy for a value not necessarily known when the promise is created. It +allows you to associate dependent promises to an asynchronous action's eventual success value or +failure reason. Promises are a way to write async code that still appears as though it is executing +in a synchronous way. + +![alt text](./etc/promise.png "Promise") + +## Applicability +Promise pattern is applicable in concurrent programming when some work needs to be done asynchronously +and: + +* code maintainablity and readability suffers due to callback hell. +* you need to compose promises and need better error handling for asynchronous tasks. +* you want to use functional style of programming. + + +## Real world examples + +* [java.util.concurrent.CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) +* [Guava ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained) + +## Related Patterns + * Async Method Invocation + * Callback + +## Credits + +* [You are missing the point to Promises](https://gist.github.com/domenic/3889970) +* [Functional style callbacks using CompleteableFuture](https://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture) From 94c3a2caf3cccba03197a53fb6c3e03190036d8f Mon Sep 17 00:00:00 2001 From: Sumit Yadav Date: Wed, 3 Aug 2016 15:02:46 +0530 Subject: [PATCH 007/492] removed extra "is" from the javadoc of InitializingOnDemandHolderIdiom class --- .../com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java index 4aa6afe12..0c450c60c 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java +++ b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java @@ -26,7 +26,7 @@ package com.iluwatar.singleton; * The Initialize-on-demand-holder idiom is a secure way of creating a lazy initialized singleton * object in Java. *

- * The technique is is as lazy as possible and works in all known versions of Java. It takes advantage + * The technique is as lazy as possible and works in all known versions of Java. It takes advantage * of language guarantees about class initialization, and will therefore work correctly in all * Java-compliant compilers and virtual machines. *

From 76970633b8a654e05d4341e96ee639bc3bcde969 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Thu, 4 Aug 2016 18:10:50 +0530 Subject: [PATCH 008/492] Work on #403, incorporate review changes --- promise/README.md | 5 +- promise/etc/promise.ucls | 46 ++++++------ .../main/java/com/iluwatar/promise/App.java | 73 +++++++++++++++---- .../java/com/iluwatar/promise/Promise.java | 16 ++-- .../com/iluwatar/promise/PromiseSupport.java | 14 ++-- 5 files changed, 100 insertions(+), 54 deletions(-) diff --git a/promise/README.md b/promise/README.md index 069a8dbfe..638bb3ef5 100644 --- a/promise/README.md +++ b/promise/README.md @@ -3,10 +3,11 @@ layout: pattern title: Promise folder: promise permalink: /patterns/promise/ -categories: Structural +categories: Concurrency tags: - Java - - Concurrency + - Functional + - Reactive - Difficulty-Intermediate --- diff --git a/promise/etc/promise.ucls b/promise/etc/promise.ucls index fe3c6c2e0..cdfb6ed7f 100644 --- a/promise/etc/promise.ucls +++ b/promise/etc/promise.ucls @@ -74,38 +74,38 @@ - - - - - - - - - + - - - - - - - - - - - - - + + + + + - + + + + + + + + + + + + + + + + + diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 6ce7de994..3a1ecfa01 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -22,6 +22,15 @@ */ package com.iluwatar.promise; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; @@ -44,6 +53,8 @@ import java.util.concurrent.Executors; *

  • Prevents callback hell and provides callback aggregation * * + *

    + * * @see CompletableFuture */ public class App { @@ -68,23 +79,57 @@ public class App { private static void promiseUsage(Executor executor) throws InterruptedException, ExecutionException { - Promise consumedPromise = new Promise<>(); - consumedPromise.fulfillInAsync(() -> { - Thread.sleep(1000); - return 10; - }, executor).then(value -> { - System.out.println("Consumed int value: " + value); + String urlString = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; + Promise lineCountPromise = new Promise().fulfillInAsync(() -> { + return downloadFile(urlString); + }, executor).then(fileLocation -> { + return countLines(fileLocation); }); - Promise transformedPromise = new Promise<>(); - transformedPromise.fulfillInAsync(() -> { - Thread.sleep(1000); - return "10"; - }, executor).then(value -> { return Integer.parseInt(value); }).then(value -> { - System.out.println("Consumed transformed int value: " + value); + Promise> charFrequencyPromise = new Promise().fulfillInAsync(() -> { + return String.valueOf(downloadFile(urlString)); + }, executor).then(fileLocation -> { + return characterFrequency(fileLocation); }); - consumedPromise.get(); - transformedPromise.get(); + lineCountPromise.get(); + System.out.println("Line count is: " + lineCountPromise.get()); + charFrequencyPromise.get(); + System.out.println("Char frequency is: " + charFrequencyPromise.get()); + } + + private static Map characterFrequency(String fileLocation) { + // TODO Auto-generated method stub + return null; + } + + private static Integer countLines(String fileLocation) { + int lineCount = 0; + try (Reader reader = new FileReader(fileLocation); + BufferedReader bufferedReader = new BufferedReader(reader);) { + for (String line; (line = bufferedReader.readLine()) != null; ) { + lineCount++; + } + } catch (IOException ex) { + ex.printStackTrace(); + } + return lineCount; + } + + private static String downloadFile(String urlString) throws InterruptedException, IOException { + URL url = new URL(urlString); + File file = File.createTempFile("promise_pattern", null); + try (Reader reader = new InputStreamReader(url.openStream()); + BufferedReader bufferedReader = new BufferedReader(reader); + FileWriter writer = new FileWriter(file)) { + for (String line; (line = bufferedReader.readLine()) != null; ) { + writer.write(line); + writer.write("\n"); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + System.out.println("File downloaded at: " + file.getAbsolutePath()); + return file.getAbsolutePath(); } } diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index fe7dc6f9f..7d8a97e84 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -120,11 +120,11 @@ public class Promise extends PromiseSupport { */ private class ConsumeAction implements Runnable { - private Promise src; - private Promise dest; - private Consumer action; + private final Promise src; + private final Promise dest; + private final Consumer action; - ConsumeAction(Promise src, Promise dest, Consumer action) { + private ConsumeAction(Promise src, Promise dest, Consumer action) { this.src = src; this.dest = dest; this.action = action; @@ -147,11 +147,11 @@ public class Promise extends PromiseSupport { */ private class TransformAction implements Runnable { - private Promise src; - private Promise dest; - private Function func; + private final Promise src; + private final Promise dest; + private final Function func; - TransformAction(Promise src, Promise dest, Function func) { + private TransformAction(Promise src, Promise dest, Function func) { this.src = src; this.dest = dest; this.func = func; diff --git a/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java index dde2ca452..048586e23 100644 --- a/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java +++ b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java @@ -33,15 +33,15 @@ import java.util.concurrent.TimeoutException; */ class PromiseSupport implements Future { - static final int RUNNING = 1; - static final int FAILED = 2; - static final int COMPLETED = 3; + private static final int RUNNING = 1; + private static final int FAILED = 2; + private static final int COMPLETED = 3; - final Object lock; + private final Object lock; - volatile int state = RUNNING; - T value; - Exception exception; + private volatile int state = RUNNING; + private T value; + private Exception exception; PromiseSupport() { this.lock = new Object(); From d484e7f731fe36832b4dd3ee690c1180bcc6117b Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Fri, 5 Aug 2016 14:38:25 +0530 Subject: [PATCH 009/492] Documented singleton double check idiom, explaining the dynamics that happen on each step for better understanding. Did this due to a PR #475 --- .../iluwatar/singleton/ThreadSafeDoubleCheckLocking.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java index 50203609c..a8fd9648a 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java +++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java @@ -53,11 +53,20 @@ public final class ThreadSafeDoubleCheckLocking { public static ThreadSafeDoubleCheckLocking getInstance() { // local variable increases performance by 25 percent // Joshua Bloch "Effective Java, Second Edition", p. 283-284 + ThreadSafeDoubleCheckLocking result = instance; + // Check if singleton instance is initialized. If it is initialized then we can return the instance. if (result == null) { + // It is not initialized but we cannot be sure because some other thread might have initialized it + // in the meanwhile. So to make sure we need to lock on an object to get mutual exclusion. synchronized (ThreadSafeDoubleCheckLocking.class) { + // Again assign the instance to local variable to check if it was initialized by some other thread + // while current thread was blocked to enter the locked zone. If it was initialized then we can + // return the previously created instance just like the previous null check. result = instance; if (result == null) { + // The instance is still not initialized so we can safely (no other thread can enter this zone) + // create an instance and make it our singleton instance. instance = result = new ThreadSafeDoubleCheckLocking(); } } From ffbc5f2f295784b30073b9b339518c590b95397a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 13 Aug 2016 17:08:57 +0300 Subject: [PATCH 010/492] Reorganize LotteryNumbers for easier inclusion in the blog --- .../hexagonal/domain/LotteryNumbers.java | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java index 6f54e743b..69d654657 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java @@ -79,6 +79,47 @@ public class LotteryNumbers { return Collections.unmodifiableSet(numbers); } + /** + * Generates 4 unique random numbers between 1-20 into numbers set. + */ + private void generateRandomNumbers() { + numbers.clear(); + RandomNumberGenerator generator = new RandomNumberGenerator(MIN_NUMBER, MAX_NUMBER); + while (numbers.size() < NUM_NUMBERS) { + int num = generator.nextInt(); + if (!numbers.contains(num)) { + numbers.add(num); + } + } + } + + /** + * + * Helper class for generating random numbers. + * + */ + private static class RandomNumberGenerator { + + private PrimitiveIterator.OfInt randomIterator; + + /** + * Initialize a new random number generator that generates random numbers in the range [min, max] + * + * @param min the min value (inclusive) + * @param max the max value (inclusive) + */ + public RandomNumberGenerator(int min, int max) { + randomIterator = new Random().ints(min, max + 1).iterator(); + } + + /** + * @return a random number in the range (min, max) + */ + public int nextInt() { + return randomIterator.nextInt(); + } + } + @Override public int hashCode() { final int prime = 31; @@ -107,46 +148,5 @@ public class LotteryNumbers { return false; } return true; - } - - /** - * Generates 4 unique random numbers between 1-20 into numbers set. - */ - private void generateRandomNumbers() { - numbers.clear(); - RandomNumberGenerator generator = new RandomNumberGenerator(MIN_NUMBER, MAX_NUMBER); - while (numbers.size() < NUM_NUMBERS) { - int num = generator.nextInt(); - if (!numbers.contains(num)) { - numbers.add(num); - } - } - } - - /** - * - * Helper class for generating random numbers. - * - */ - private static class RandomNumberGenerator { - - private PrimitiveIterator.OfInt randomIterator; - - /** - * Initialize a new random number generator that generates random numbers in the range [min, max] - * - * @param min the min value (inclusive) - * @param max the max value (inclusive) - */ - public RandomNumberGenerator(int min, int max) { - randomIterator = new Random().ints(min, max + 1).iterator(); - } - - /** - * @return a random number in the range (min, max) - */ - public int nextInt() { - return randomIterator.nextInt(); - } - } + } } From 7c2f5da9260357437a884d2117ae5d292d8eb800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 13 Aug 2016 18:28:53 +0300 Subject: [PATCH 011/492] Add final keyword --- hexagonal/src/main/java/com/iluwatar/hexagonal/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java index 3ae55b706..0f7239a89 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java @@ -69,7 +69,7 @@ import com.iluwatar.hexagonal.service.LotteryServiceImpl; */ public class App { - private static List allPlayerDetails; + private static final List allPlayerDetails; static { allPlayerDetails = new ArrayList<>(); From 0b36a3153d6b4aef7604b26259ca03fa89a3b4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 14 Aug 2016 22:42:59 +0300 Subject: [PATCH 012/492] Fix checkstyle error --- .../main/java/com/iluwatar/hexagonal/App.java | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java index 0f7239a89..92ebf3572 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java @@ -69,53 +69,53 @@ import com.iluwatar.hexagonal.service.LotteryServiceImpl; */ public class App { - private static final List allPlayerDetails; + private static final List PLAYERS; static { - allPlayerDetails = new ArrayList<>(); - allPlayerDetails.add(PlayerDetails.create("john@google.com", "312-342", "+3242434242")); - allPlayerDetails.add(PlayerDetails.create("mary@google.com", "234-987", "+23452346")); - allPlayerDetails.add(PlayerDetails.create("steve@google.com", "833-836", "+63457543")); - allPlayerDetails.add(PlayerDetails.create("wayne@google.com", "319-826", "+24626")); - allPlayerDetails.add(PlayerDetails.create("johnie@google.com", "983-322", "+3635635")); - allPlayerDetails.add(PlayerDetails.create("andy@google.com", "934-734", "+0898245")); - allPlayerDetails.add(PlayerDetails.create("richard@google.com", "536-738", "+09845325")); - allPlayerDetails.add(PlayerDetails.create("kevin@google.com", "453-936", "+2423532")); - allPlayerDetails.add(PlayerDetails.create("arnold@google.com", "114-988", "+5646346524")); - allPlayerDetails.add(PlayerDetails.create("ian@google.com", "663-765", "+928394235")); - allPlayerDetails.add(PlayerDetails.create("robin@google.com", "334-763", "+35448")); - allPlayerDetails.add(PlayerDetails.create("ted@google.com", "735-964", "+98752345")); - allPlayerDetails.add(PlayerDetails.create("larry@google.com", "734-853", "+043842423")); - allPlayerDetails.add(PlayerDetails.create("calvin@google.com", "334-746", "+73294135")); - allPlayerDetails.add(PlayerDetails.create("jacob@google.com", "444-766", "+358042354")); - allPlayerDetails.add(PlayerDetails.create("edwin@google.com", "895-345", "+9752435")); - allPlayerDetails.add(PlayerDetails.create("mary@google.com", "760-009", "+34203542")); - allPlayerDetails.add(PlayerDetails.create("lolita@google.com", "425-907", "+9872342")); - allPlayerDetails.add(PlayerDetails.create("bruno@google.com", "023-638", "+673824122")); - allPlayerDetails.add(PlayerDetails.create("peter@google.com", "335-886", "+5432503945")); - allPlayerDetails.add(PlayerDetails.create("warren@google.com", "225-946", "+9872341324")); - allPlayerDetails.add(PlayerDetails.create("monica@google.com", "265-748", "+134124")); - allPlayerDetails.add(PlayerDetails.create("ollie@google.com", "190-045", "+34453452")); - allPlayerDetails.add(PlayerDetails.create("yngwie@google.com", "241-465", "+9897641231")); - allPlayerDetails.add(PlayerDetails.create("lars@google.com", "746-936", "+42345298345")); - allPlayerDetails.add(PlayerDetails.create("bobbie@google.com", "946-384", "+79831742")); - allPlayerDetails.add(PlayerDetails.create("tyron@google.com", "310-992", "+0498837412")); - allPlayerDetails.add(PlayerDetails.create("tyrell@google.com", "032-045", "+67834134")); - allPlayerDetails.add(PlayerDetails.create("nadja@google.com", "000-346", "+498723")); - allPlayerDetails.add(PlayerDetails.create("wendy@google.com", "994-989", "+987324454")); - allPlayerDetails.add(PlayerDetails.create("luke@google.com", "546-634", "+987642435")); - allPlayerDetails.add(PlayerDetails.create("bjorn@google.com", "342-874", "+7834325")); - allPlayerDetails.add(PlayerDetails.create("lisa@google.com", "024-653", "+980742154")); - allPlayerDetails.add(PlayerDetails.create("anton@google.com", "834-935", "+876423145")); - allPlayerDetails.add(PlayerDetails.create("bruce@google.com", "284-936", "+09843212345")); - allPlayerDetails.add(PlayerDetails.create("ray@google.com", "843-073", "+678324123")); - allPlayerDetails.add(PlayerDetails.create("ron@google.com", "637-738", "+09842354")); - allPlayerDetails.add(PlayerDetails.create("xavier@google.com", "143-947", "+375245")); - allPlayerDetails.add(PlayerDetails.create("harriet@google.com", "842-404", "+131243252")); + PLAYERS = new ArrayList<>(); + PLAYERS.add(PlayerDetails.create("john@google.com", "312-342", "+3242434242")); + PLAYERS.add(PlayerDetails.create("mary@google.com", "234-987", "+23452346")); + PLAYERS.add(PlayerDetails.create("steve@google.com", "833-836", "+63457543")); + PLAYERS.add(PlayerDetails.create("wayne@google.com", "319-826", "+24626")); + PLAYERS.add(PlayerDetails.create("johnie@google.com", "983-322", "+3635635")); + PLAYERS.add(PlayerDetails.create("andy@google.com", "934-734", "+0898245")); + PLAYERS.add(PlayerDetails.create("richard@google.com", "536-738", "+09845325")); + PLAYERS.add(PlayerDetails.create("kevin@google.com", "453-936", "+2423532")); + PLAYERS.add(PlayerDetails.create("arnold@google.com", "114-988", "+5646346524")); + PLAYERS.add(PlayerDetails.create("ian@google.com", "663-765", "+928394235")); + PLAYERS.add(PlayerDetails.create("robin@google.com", "334-763", "+35448")); + PLAYERS.add(PlayerDetails.create("ted@google.com", "735-964", "+98752345")); + PLAYERS.add(PlayerDetails.create("larry@google.com", "734-853", "+043842423")); + PLAYERS.add(PlayerDetails.create("calvin@google.com", "334-746", "+73294135")); + PLAYERS.add(PlayerDetails.create("jacob@google.com", "444-766", "+358042354")); + PLAYERS.add(PlayerDetails.create("edwin@google.com", "895-345", "+9752435")); + PLAYERS.add(PlayerDetails.create("mary@google.com", "760-009", "+34203542")); + PLAYERS.add(PlayerDetails.create("lolita@google.com", "425-907", "+9872342")); + PLAYERS.add(PlayerDetails.create("bruno@google.com", "023-638", "+673824122")); + PLAYERS.add(PlayerDetails.create("peter@google.com", "335-886", "+5432503945")); + PLAYERS.add(PlayerDetails.create("warren@google.com", "225-946", "+9872341324")); + PLAYERS.add(PlayerDetails.create("monica@google.com", "265-748", "+134124")); + PLAYERS.add(PlayerDetails.create("ollie@google.com", "190-045", "+34453452")); + PLAYERS.add(PlayerDetails.create("yngwie@google.com", "241-465", "+9897641231")); + PLAYERS.add(PlayerDetails.create("lars@google.com", "746-936", "+42345298345")); + PLAYERS.add(PlayerDetails.create("bobbie@google.com", "946-384", "+79831742")); + PLAYERS.add(PlayerDetails.create("tyron@google.com", "310-992", "+0498837412")); + PLAYERS.add(PlayerDetails.create("tyrell@google.com", "032-045", "+67834134")); + PLAYERS.add(PlayerDetails.create("nadja@google.com", "000-346", "+498723")); + PLAYERS.add(PlayerDetails.create("wendy@google.com", "994-989", "+987324454")); + PLAYERS.add(PlayerDetails.create("luke@google.com", "546-634", "+987642435")); + PLAYERS.add(PlayerDetails.create("bjorn@google.com", "342-874", "+7834325")); + PLAYERS.add(PlayerDetails.create("lisa@google.com", "024-653", "+980742154")); + PLAYERS.add(PlayerDetails.create("anton@google.com", "834-935", "+876423145")); + PLAYERS.add(PlayerDetails.create("bruce@google.com", "284-936", "+09843212345")); + PLAYERS.add(PlayerDetails.create("ray@google.com", "843-073", "+678324123")); + PLAYERS.add(PlayerDetails.create("ron@google.com", "637-738", "+09842354")); + PLAYERS.add(PlayerDetails.create("xavier@google.com", "143-947", "+375245")); + PLAYERS.add(PlayerDetails.create("harriet@google.com", "842-404", "+131243252")); WireTransfersImpl wireTransfers = new WireTransfersImpl(); Random random = new Random(); - for (int i = 0; i < allPlayerDetails.size(); i++) { - wireTransfers.setFunds(allPlayerDetails.get(i).getBankAccount(), + for (int i = 0; i < PLAYERS.size(); i++) { + wireTransfers.setFunds(PLAYERS.get(i).getBankAccount(), random.nextInt(LotteryConstants.PLAYER_MAX_SALDO)); } } @@ -145,7 +145,7 @@ public class App { private static PlayerDetails getRandomPlayerDetails() { Random random = new Random(); - int idx = random.nextInt(allPlayerDetails.size()); - return allPlayerDetails.get(idx); + int idx = random.nextInt(PLAYERS.size()); + return PLAYERS.get(idx); } } From b16d7fc970538c0f8194a5dc7db567d0e8b16546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 14 Aug 2016 23:00:27 +0300 Subject: [PATCH 013/492] Configure Travis notification email --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index deb436cd2..bcbad6827 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,4 +15,8 @@ after_success: - mvn clean test jacoco:report coveralls:report - bash update-ghpages.sh +notifications: + email: + - iluwatar@gmail.com + sudo: false # route the build to the container-based infrastructure for a faster build From 7e77216919c0c5cef6e67e477c2ee93ee16f25f8 Mon Sep 17 00:00:00 2001 From: Markus Moser Date: Mon, 15 Aug 2016 11:53:39 +0200 Subject: [PATCH 014/492] remove link, resolves #479 to avoid confusion, the link is removed. For more information on why this is done please look at the referenced issue --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 811d6a17a..1789398ec 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ are familiar with the patterns. # Getting started Before you dive into the material, you should be familiar with various -[Programming/Software Design Principles](http://webpro.github.io/programming-principles/). +Programming/Software Design Principles. All designs should be as simple as possible. You should start with KISS, YAGNI, and Do The Simplest Thing That Could Possibly Work principles. Complexity and From 56100927a9537831e6d73d20d3a43840f1fc2d9b Mon Sep 17 00:00:00 2001 From: Markus Moser Date: Mon, 15 Aug 2016 12:33:24 +0200 Subject: [PATCH 015/492] Addendum #481 Change page-index for faq.md --- faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/faq.md b/faq.md index 69f7b795e..2280b42f5 100644 --- a/faq.md +++ b/faq.md @@ -3,7 +3,7 @@ layout: page title: FAQ permalink: /faq/ icon: fa-question -page-index: 1 +page-index: 5 --- ### Q1: What is the difference between State and Strategy patterns? {#Q1} From c79df708b14115176721aa8dbda1ccd97f88da37 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sat, 20 Aug 2016 13:17:53 +0530 Subject: [PATCH 016/492] #211 added real world examples from Java api for creational patterns --- abstract-factory/README.md | 4 +++- builder/README.md | 3 +++ factory-method/README.md | 12 ++++++++---- singleton/README.md | 3 +++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/abstract-factory/README.md b/abstract-factory/README.md index 485599b98..fd669551d 100644 --- a/abstract-factory/README.md +++ b/abstract-factory/README.md @@ -4,7 +4,7 @@ title: Abstract Factory folder: abstract-factory permalink: /patterns/abstract-factory/ categories: Creational -tags: +tags: - Java - Gang Of Four - Difficulty-Intermediate @@ -30,6 +30,8 @@ Use the Abstract Factory pattern when ## Real world examples * [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) +* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--) +* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--) ## Credits diff --git a/builder/README.md b/builder/README.md index 5d1f3d24d..9f374d94d 100644 --- a/builder/README.md +++ b/builder/README.md @@ -26,6 +26,9 @@ Use the Builder pattern when ## Real world examples * [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html) +* [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-) as well as similar buffers such as FloatBuffer, IntBuffer and so on. +* [java.lang.StringBuffer](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-) +* All implementations of [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html) * [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder) ## Credits diff --git a/factory-method/README.md b/factory-method/README.md index 05549cf4f..c379e9609 100644 --- a/factory-method/README.md +++ b/factory-method/README.md @@ -4,7 +4,7 @@ title: Factory Method folder: factory-method permalink: /patterns/factory-method/ categories: Creational -tags: +tags: - Java - Difficulty-Beginner - Gang Of Four @@ -29,9 +29,13 @@ Use the Factory Method pattern when ## Known uses -* java.util.Calendar -* java.util.ResourceBundle -* java.text.NumberFormat#getInstance() +* [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) +* [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) +* [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) +* [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) +* [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-) +* [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-) +* [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) ## Credits diff --git a/singleton/README.md b/singleton/README.md index 2a481f5c8..f821752ba 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -31,6 +31,9 @@ Use the Singleton pattern when ## Real world examples * [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29) +* [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--) +* [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--) + ## Credits From eb75773891360ff8f872fa4aea0fd3acb2f6c034 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sat, 20 Aug 2016 19:44:48 +0530 Subject: [PATCH 017/492] Added FAQ on Memento pattern Difference between java Serialization and Memento pattern added --- faq.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/faq.md b/faq.md index 2280b42f5..01a7e7b72 100644 --- a/faq.md +++ b/faq.md @@ -65,3 +65,11 @@ Flyweight. ### Q7: What are the differences between FluentInterface and Builder patterns? {#Q7} Fluent interfaces are sometimes confused with the Builder pattern, because they share method chaining and a fluent usage. However, fluent interfaces are not primarily used to create shared (mutable) objects, but to configure complex objects without having to respecify the target object on every property change. + +### Q8: What is the difference between java.io.Serialization and Memento pattern? {#Q8} + +Memento is typically used to implement rollback/save-point support. Example we might want to mark the state of an object at a point in time, do some work and then decide to rollback to the previous state. + +On the other hand serialization may be used as a tool to save the state of an object into byte[] and preserving the contents in memory or disk. When someone invokes the memento to revert object's previous state then we can deserialize the information stored and recreate previous state. + +So Memento is a pattern and serialization is a tool that can be used to implement this pattern. Other ways to implement the pattern can be to clone the contents of the object and keep track of those clones. From a0c77c32b58dec68b75a65ed8de4e0eff966ae15 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sat, 20 Aug 2016 20:49:28 +0530 Subject: [PATCH 018/492] #211 added further examples for structural and behavioral patterns --- adapter/README.md | 4 ++++ chain/README.md | 1 + command/README.md | 3 ++- decorator/README.md | 8 ++++++++ flyweight/README.md | 4 ++-- interpreter/README.md | 9 ++++++++- iterator/README.md | 3 ++- mediator/README.md | 10 +++++++++- observer/README.md | 4 +++- state/README.md | 5 +++++ visitor/README.md | 3 +++ 11 files changed, 47 insertions(+), 7 deletions(-) diff --git a/adapter/README.md b/adapter/README.md index ea3baa7fa..6f517127f 100644 --- a/adapter/README.md +++ b/adapter/README.md @@ -30,6 +30,10 @@ Use the Adapter pattern when ## Real world examples * [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) +* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-) +* [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-) +* [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-) + ## Credits diff --git a/chain/README.md b/chain/README.md index ef18f6f64..0bf73fb92 100644 --- a/chain/README.md +++ b/chain/README.md @@ -28,6 +28,7 @@ Use Chain of Responsibility when * [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29) * [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html) +* [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-) ## Credits diff --git a/command/README.md b/command/README.md index a5478394c..987ec6a34 100644 --- a/command/README.md +++ b/command/README.md @@ -4,7 +4,7 @@ title: Command folder: command permalink: /patterns/command/ categories: Behavioral -tags: +tags: - Java - Gang Of Four - Difficulty-Intermediate @@ -40,6 +40,7 @@ Use the Command pattern when you want to * [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html) * [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki) +* [javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html) ## Credits diff --git a/decorator/README.md b/decorator/README.md index 63795114c..9acf417ad 100644 --- a/decorator/README.md +++ b/decorator/README.md @@ -27,6 +27,14 @@ Use Decorator * for responsibilities that can be withdrawn * when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing +## Real World examples + * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), + [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) and [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) + * [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) + * [java.util.Collections#unmodifiableXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableCollection-java.util.Collection-) + * [java.util.Collections#checkedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#checkedCollection-java.util.Collection-java.lang.Class-) + + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/flyweight/README.md b/flyweight/README.md index a98dced8e..5bb8eb380 100644 --- a/flyweight/README.md +++ b/flyweight/README.md @@ -4,7 +4,7 @@ title: Flyweight folder: flyweight permalink: /patterns/flyweight/ categories: Structural -tags: +tags: - Java - Gang Of Four - Difficulty-Intermediate @@ -30,7 +30,7 @@ true ## Real world examples -* [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29) +* [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29) and similarly for Byte, Character and other wrapped types. ## Credits diff --git a/interpreter/README.md b/interpreter/README.md index 87c1c47f7..4fcc5e6ff 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -4,7 +4,7 @@ title: Interpreter folder: interpreter permalink: /patterns/interpreter/ categories: Behavioral -tags: +tags: - Java - Gang Of Four - Difficulty-Intermediate @@ -25,6 +25,13 @@ trees. The Interpreter pattern works best when * the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time * efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable +## Real World Applications +* [java.util.Pattern](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) +* [java.text.Normalizer](http://docs.oracle.com/javase/8/docs/api/java/text/Normalizer.html) +* All subclasses of [java.text.Format](http://docs.oracle.com/javase/8/docs/api/java/text/Format.html) +* [javax.el.ELResolver](http://docs.oracle.com/javaee/7/api/javax/el/ELResolver.html) + + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/iterator/README.md b/iterator/README.md index d6be7758d..723e7f03c 100644 --- a/iterator/README.md +++ b/iterator/README.md @@ -4,7 +4,7 @@ title: Iterator folder: iterator permalink: /patterns/iterator/ categories: Behavioral -tags: +tags: - Java - Difficulty-Beginner - Gang Of Four @@ -29,6 +29,7 @@ Use the Iterator pattern ## Real world examples * [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html) +* [java.util.Enumeration](http://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html) ## Credits diff --git a/mediator/README.md b/mediator/README.md index c7a0478c8..5a784bbcb 100644 --- a/mediator/README.md +++ b/mediator/README.md @@ -24,6 +24,14 @@ Use the Mediator pattern when * reusing an object is difficult because it refers to and communicates with many other objects * a behavior that's distributed between several classes should be customizable without a lot of subclassing +## Real World Applications + +* All scheduleXXX() methods of [java.util.Timer](http://docs.oracle.com/javase/8/docs/api/java/util/Timer.html) +* [java.util.concurrent.Executor#execute()](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-) +* submit() and invokeXXX() methods of [java.util.concurrent.ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) +* scheduleXXX() methods of [java.util.concurrent.ScheduledExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html) +* [java.lang.reflect.Method#invoke()](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#invoke-java.lang.Object-java.lang.Object...-) + ## Credits -* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/observer/README.md b/observer/README.md index 6fbe3cdab..e25359f02 100644 --- a/observer/README.md +++ b/observer/README.md @@ -4,7 +4,7 @@ title: Observer folder: observer permalink: /patterns/observer/ categories: Behavioral -tags: +tags: - Java - Difficulty-Beginner - Gang Of Four @@ -35,6 +35,8 @@ Use the Observer pattern in any of the following situations ## Real world examples * [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html) +* [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html) +* [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html) ## Credits diff --git a/state/README.md b/state/README.md index f5cb189fd..948c62a08 100644 --- a/state/README.md +++ b/state/README.md @@ -25,6 +25,11 @@ Use the State pattern in either of the following cases * an object's behavior depends on its state, and it must change its behavior at run-time depending on that state * operations have large, multipart conditional statements that depend on the object's state. This state is usually represented by one or more enumerated constants. Often, several operations will contain this same conditional structure. The State pattern puts each branch of the conditional in a separate class. This lets you treat the object's state as an object in its own right that can vary independently from other objects. +## Real world applications + +* [javax.faces.lifecycle.Lifecycle#execute()](http://docs.oracle.com/javaee/7/api/javax/faces/lifecycle/Lifecycle.html#execute-javax.faces.context.FacesContext-) controlled by [FacesServlet](http://docs.oracle.com/javaee/7/api/javax/faces/webapp/FacesServlet.html), the behavior is dependent on current phase of lifecycle. +* [JDiameter - Diameter State Machine](https://github.com/npathai/jdiameter/blob/master/core/jdiameter/api/src/main/java/org/jdiameter/api/app/State.java) + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/visitor/README.md b/visitor/README.md index c1e24a624..bda789a18 100644 --- a/visitor/README.md +++ b/visitor/README.md @@ -27,6 +27,9 @@ Use the Visitor pattern when ## Real world examples * [Apache Wicket](https://github.com/apache/wicket) component tree, see [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java) +* [javax.lang.model.element.AnnotationValue](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/AnnotationValue.html) and [AnnotationValueVisitor](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/AnnotationValueVisitor.html) +* [javax.lang.model.element.Element](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/Element.html) and [Element Visitor](http://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/ElementVisitor.html) +* [java.nio.file.FileVisitor](http://docs.oracle.com/javase/8/docs/api/java/nio/file/FileVisitor.html) ## Credits From 28647cdf482e878bb28ae535ae9c23cc1992f8a5 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sat, 20 Aug 2016 20:57:48 +0530 Subject: [PATCH 019/492] #211, consistent use of real world examples section in all readme files. --- decorator/README.md | 4 ++-- interpreter/README.md | 2 +- mediator/README.md | 2 +- state/README.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/decorator/README.md b/decorator/README.md index 9acf417ad..08f869645 100644 --- a/decorator/README.md +++ b/decorator/README.md @@ -27,13 +27,13 @@ Use Decorator * for responsibilities that can be withdrawn * when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing -## Real World examples +## Real world examples * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) and [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) * [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) * [java.util.Collections#unmodifiableXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableCollection-java.util.Collection-) * [java.util.Collections#checkedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#checkedCollection-java.util.Collection-java.lang.Class-) - + ## Credits diff --git a/interpreter/README.md b/interpreter/README.md index 4fcc5e6ff..be6517962 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -25,7 +25,7 @@ trees. The Interpreter pattern works best when * the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time * efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable -## Real World Applications +## Real world examples * [java.util.Pattern](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) * [java.text.Normalizer](http://docs.oracle.com/javase/8/docs/api/java/text/Normalizer.html) * All subclasses of [java.text.Format](http://docs.oracle.com/javase/8/docs/api/java/text/Format.html) diff --git a/mediator/README.md b/mediator/README.md index 5a784bbcb..3452082ef 100644 --- a/mediator/README.md +++ b/mediator/README.md @@ -24,7 +24,7 @@ Use the Mediator pattern when * reusing an object is difficult because it refers to and communicates with many other objects * a behavior that's distributed between several classes should be customizable without a lot of subclassing -## Real World Applications +## Real world examples * All scheduleXXX() methods of [java.util.Timer](http://docs.oracle.com/javase/8/docs/api/java/util/Timer.html) * [java.util.concurrent.Executor#execute()](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-) diff --git a/state/README.md b/state/README.md index 948c62a08..549afa61f 100644 --- a/state/README.md +++ b/state/README.md @@ -25,7 +25,7 @@ Use the State pattern in either of the following cases * an object's behavior depends on its state, and it must change its behavior at run-time depending on that state * operations have large, multipart conditional statements that depend on the object's state. This state is usually represented by one or more enumerated constants. Often, several operations will contain this same conditional structure. The State pattern puts each branch of the conditional in a separate class. This lets you treat the object's state as an object in its own right that can vary independently from other objects. -## Real world applications +## Real world examples * [javax.faces.lifecycle.Lifecycle#execute()](http://docs.oracle.com/javaee/7/api/javax/faces/lifecycle/Lifecycle.html#execute-javax.faces.context.FacesContext-) controlled by [FacesServlet](http://docs.oracle.com/javaee/7/api/javax/faces/webapp/FacesServlet.html), the behavior is dependent on current phase of lifecycle. * [JDiameter - Diameter State Machine](https://github.com/npathai/jdiameter/blob/master/core/jdiameter/api/src/main/java/org/jdiameter/api/app/State.java) From 95cf9fe367c7c7c58e80f9b35ef5db0ca00c63e5 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Mon, 22 Aug 2016 18:43:29 +0530 Subject: [PATCH 020/492] Work on #403, made example readable and moved methods into utility --- promise/etc/promise.png | Bin 59544 -> 55725 bytes promise/etc/promise.ucls | 30 ++--- .../main/java/com/iluwatar/promise/App.java | 127 ++++++++++-------- .../java/com/iluwatar/promise/Utility.java | 91 +++++++++++++ 4 files changed, 172 insertions(+), 76 deletions(-) create mode 100644 promise/src/main/java/com/iluwatar/promise/Utility.java diff --git a/promise/etc/promise.png b/promise/etc/promise.png index 1a0f671080915d26268f2ce16df59c430a14926e..0aef198acb4e9abdb4cf5b34f61869b46e870c8a 100644 GIT binary patch literal 55725 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 B1!4dI literal 59544 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 diff --git a/promise/etc/promise.ucls b/promise/etc/promise.ucls index cdfb6ed7f..e7fefec1c 100644 --- a/promise/etc/promise.ucls +++ b/promise/etc/promise.ucls @@ -25,7 +25,7 @@ - + @@ -67,42 +67,38 @@ - + - + - - - - - + - + + + + + - - - - - + - - - + + + diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 3a1ecfa01..1315f0927 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -21,19 +21,10 @@ * THE SOFTWARE. */ package com.iluwatar.promise; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -59,7 +50,12 @@ import java.util.concurrent.Executors; */ public class App { + private static final String URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; + private ExecutorService executor; + private CountDownLatch canStop = new CountDownLatch(2); + private App() { + executor = Executors.newFixedThreadPool(2); } /** @@ -69,67 +65,80 @@ public class App { * @throws ExecutionException if an execution error occurs. */ public static void main(String[] args) throws InterruptedException, ExecutionException { - ExecutorService executor = Executors.newSingleThreadExecutor(); + App app = new App(); try { - promiseUsage(executor); + app.run(); } finally { - executor.shutdownNow(); + app.stop(); } } - private static void promiseUsage(Executor executor) - throws InterruptedException, ExecutionException { - String urlString = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; - Promise lineCountPromise = new Promise().fulfillInAsync(() -> { - return downloadFile(urlString); - }, executor).then(fileLocation -> { - return countLines(fileLocation); - }); + private void run() throws InterruptedException, ExecutionException { + promiseUsage(); + } + + private void promiseUsage() { - Promise> charFrequencyPromise = new Promise().fulfillInAsync(() -> { - return String.valueOf(downloadFile(urlString)); - }, executor).then(fileLocation -> { - return characterFrequency(fileLocation); - }); + countLines() + .then( + count -> { + System.out.println("Line count is: " + count); + taskCompleted(); + } + ); - lineCountPromise.get(); - System.out.println("Line count is: " + lineCountPromise.get()); - charFrequencyPromise.get(); - System.out.println("Char frequency is: " + charFrequencyPromise.get()); + lowestCharFrequency() + .then( + charFrequency -> { + System.out.println("Char with lowest frequency is: " + charFrequency); + taskCompleted(); + } + ); } - private static Map characterFrequency(String fileLocation) { - // TODO Auto-generated method stub - return null; + private Promise lowestCharFrequency() { + return characterFrequency() + .then( + charFrequency -> { + return Utility.lowestFrequencyChar(charFrequency).orElse(null); + } + ); } - private static Integer countLines(String fileLocation) { - int lineCount = 0; - try (Reader reader = new FileReader(fileLocation); - BufferedReader bufferedReader = new BufferedReader(reader);) { - for (String line; (line = bufferedReader.readLine()) != null; ) { - lineCount++; - } - } catch (IOException ex) { - ex.printStackTrace(); - } - return lineCount; + private Promise> characterFrequency() { + return download(URL) + .then( + fileLocation -> { + return Utility.characterFrequency(fileLocation); + } + ); } - private static String downloadFile(String urlString) throws InterruptedException, IOException { - URL url = new URL(urlString); - File file = File.createTempFile("promise_pattern", null); - try (Reader reader = new InputStreamReader(url.openStream()); - BufferedReader bufferedReader = new BufferedReader(reader); - FileWriter writer = new FileWriter(file)) { - for (String line; (line = bufferedReader.readLine()) != null; ) { - writer.write(line); - writer.write("\n"); - } - } catch (IOException ex) { - ex.printStackTrace(); - } - System.out.println("File downloaded at: " + file.getAbsolutePath()); - return file.getAbsolutePath(); + private Promise countLines() { + return download(URL) + .then( + fileLocation -> { + return Utility.countLines(fileLocation); + } + ); + } + + private Promise download(String urlString) { + Promise downloadPromise = new Promise() + .fulfillInAsync( + () -> { + return Utility.downloadFile(urlString); + }, executor); + + return downloadPromise; + } + + private void stop() throws InterruptedException { + canStop.await(); + executor.shutdownNow(); + } + + private void taskCompleted() { + canStop.countDown(); } } diff --git a/promise/src/main/java/com/iluwatar/promise/Utility.java b/promise/src/main/java/com/iluwatar/promise/Utility.java new file mode 100644 index 000000000..2cfad46d0 --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/Utility.java @@ -0,0 +1,91 @@ +package com.iluwatar.promise; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Optional; +import java.util.Map.Entry; + +public class Utility { + + public static Map characterFrequency(String fileLocation) { + Map characterToFrequency = new HashMap<>(); + try (Reader reader = new FileReader(fileLocation); + BufferedReader bufferedReader = new BufferedReader(reader);) { + for (String line; (line = bufferedReader.readLine()) != null;) { + for (char c : line.toCharArray()) { + if (!characterToFrequency.containsKey(c)) { + characterToFrequency.put(c, 1); + } else { + characterToFrequency.put(c, characterToFrequency.get(c) + 1); + } + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + return characterToFrequency; + } + + public static Optional lowestFrequencyChar(Map charFrequency) { + Optional lowestFrequencyChar = Optional.empty(); + if (charFrequency.isEmpty()) { + return lowestFrequencyChar; + } + + Iterator> iterator = charFrequency.entrySet().iterator(); + Entry entry = iterator.next(); + int minFrequency = entry.getValue(); + lowestFrequencyChar = Optional.of(entry.getKey()); + + while (iterator.hasNext()) { + entry = iterator.next(); + if (entry.getValue() < minFrequency) { + minFrequency = entry.getValue(); + lowestFrequencyChar = Optional.of(entry.getKey()); + } + } + + return lowestFrequencyChar; + } + + public static Integer countLines(String fileLocation) { + int lineCount = 0; + try (Reader reader = new FileReader(fileLocation); + BufferedReader bufferedReader = new BufferedReader(reader);) { + while (bufferedReader.readLine() != null) { + lineCount++; + } + } catch (IOException ex) { + ex.printStackTrace(); + } + return lineCount; + } + + public static String downloadFile(String urlString) throws MalformedURLException, IOException { + System.out.println("Downloading contents from url: " + urlString); + URL url = new URL(urlString); + File file = File.createTempFile("promise_pattern", null); + try (Reader reader = new InputStreamReader(url.openStream()); + BufferedReader bufferedReader = new BufferedReader(reader); + FileWriter writer = new FileWriter(file)) { + for (String line; (line = bufferedReader.readLine()) != null; ) { + writer.write(line); + writer.write("\n"); + } + System.out.println("File downloaded at: " + file.getAbsolutePath()); + return file.getAbsolutePath(); + } catch (IOException ex) { + throw ex; + } + } +} From f16ae08bdf5e4949bc1a169ef44244d8c4b30a74 Mon Sep 17 00:00:00 2001 From: Alexandru Somai Date: Fri, 26 Aug 2016 12:46:30 +0300 Subject: [PATCH 021/492] Remove extra space --- .../com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java index 472325786..c7c75143c 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java @@ -38,7 +38,7 @@ public final class ThreadSafeLazyLoadedIvoryTower { /** * The instance gets created only when it is called for first time. Lazy-loading */ - public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() { + public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() { if (instance == null) { instance = new ThreadSafeLazyLoadedIvoryTower(); From 095adda7e925e4d3925e9f6fe7d61b8018fc8d1b Mon Sep 17 00:00:00 2001 From: Alexandru Somai Date: Fri, 26 Aug 2016 12:54:20 +0300 Subject: [PATCH 022/492] Change access level to private --- .../com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java index 0c450c60c..6536978fc 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java +++ b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java @@ -53,7 +53,7 @@ public final class InitializingOnDemandHolderIdiom { * Provides the lazy-loaded Singleton instance. */ private static class HelperHolder { - public static final InitializingOnDemandHolderIdiom INSTANCE = + private static final InitializingOnDemandHolderIdiom INSTANCE = new InitializingOnDemandHolderIdiom(); } } From 483c61a82af39ba7fc9c226bf112dc8db511e429 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Mon, 29 Aug 2016 00:16:36 +0530 Subject: [PATCH 023/492] Some refactoring, added javadocs --- .../main/java/com/iluwatar/promise/App.java | 141 +++++++++++------- .../java/com/iluwatar/promise/Promise.java | 36 ++++- .../java/com/iluwatar/promise/Utility.java | 46 +++--- .../com/iluwatar/promise/PromiseTest.java | 46 ++++-- 4 files changed, 175 insertions(+), 94 deletions(-) diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 1315f0927..2b2ae78b4 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -29,35 +29,45 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** - * - *

    The Promise object is used for asynchronous computations. A Promise represents an operation that - * hasn't completed yet, but is expected in the future. - * - *

    A Promise represents a proxy for a value not necessarily known when the promise is created. It - * allows you to associate dependent promises to an asynchronous action's eventual success value or - * failure reason. This lets asynchronous methods return values like synchronous methods: instead of the final - * value, the asynchronous method returns a promise of having a value at some point in the future. - * + * + * The Promise object is used for asynchronous computations. A Promise represents an operation + * that hasn't completed yet, but is expected in the future. + * + *

    A Promise represents a proxy for a value not necessarily known when the promise is created. It + * allows you to associate dependent promises to an asynchronous action's eventual success value or + * failure reason. This lets asynchronous methods return values like synchronous methods: instead + * of the final value, the asynchronous method returns a promise of having a value at some point + * in the future. + * *

    Promises provide a few advantages over callback objects: *

    - * + * *

    + * In this application the usage of promise is demonstrated with two examples: + *

      + *
    • Count Lines: In this example a file is downloaded and its line count is calculated. + * The calculated line count is then consumed and printed on console. + *
    • Lowest Character Frequency: In this example a file is downloaded and its lowest frequency + * character is found and printed on console. This happens via a chain of promises, we start with + * a file download promise, then a promise of character frequency, then a promise of lowest frequency + * character which is finally consumed and result is printed on console. + *
    * * @see CompletableFuture */ public class App { - private static final String URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; + private static final String DEFAULT_URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; private ExecutorService executor; - private CountDownLatch canStop = new CountDownLatch(2); - + private CountDownLatch stopLatch = new CountDownLatch(2); + private App() { executor = Executors.newFixedThreadPool(2); } - + /** * Program entry point * @param args arguments @@ -67,28 +77,25 @@ public class App { public static void main(String[] args) throws InterruptedException, ExecutionException { App app = new App(); try { - app.run(); + app.promiseUsage(); } finally { app.stop(); } } - private void run() throws InterruptedException, ExecutionException { - promiseUsage(); + private void promiseUsage() { + calculateLineCount(); + + calculateLowestFrequencyChar(); } - private void promiseUsage() { - - countLines() - .then( - count -> { - System.out.println("Line count is: " + count); - taskCompleted(); - } - ); - - lowestCharFrequency() - .then( + /* + * Calculate the lowest frequency character and when that promise is fulfilled, + * consume the result in a Consumer + */ + private void calculateLowestFrequencyChar() { + lowestFrequencyChar() + .thenAccept( charFrequency -> { System.out.println("Char with lowest frequency is: " + charFrequency); taskCompleted(); @@ -96,49 +103,73 @@ public class App { ); } - private Promise lowestCharFrequency() { - return characterFrequency() - .then( - charFrequency -> { - return Utility.lowestFrequencyChar(charFrequency).orElse(null); - } - ); - } - - private Promise> characterFrequency() { - return download(URL) - .then( - fileLocation -> { - return Utility.characterFrequency(fileLocation); + /* + * Calculate the line count and when that promise is fulfilled, consume the result + * in a Consumer + */ + private void calculateLineCount() { + countLines() + .thenAccept( + count -> { + System.out.println("Line count is: " + count); + taskCompleted(); } ); } - private Promise countLines() { - return download(URL) - .then( - fileLocation -> { - return Utility.countLines(fileLocation); - } - ); + /* + * Calculate the character frequency of a file and when that promise is fulfilled, + * then promise to apply function to calculate lowest character frequency. + */ + private Promise lowestFrequencyChar() { + return characterFrequency() + .thenApply(Utility::lowestFrequencyChar); } + /* + * Download the file at DEFAULT_URL and when that promise is fulfilled, + * then promise to apply function to calculate character frequency. + */ + private Promise> characterFrequency() { + return download(DEFAULT_URL) + .thenApply(Utility::characterFrequency); + } + + /* + * Download the file at DEFAULT_URL and when that promise is fulfilled, + * then promise to apply function to count lines in that file. + */ + private Promise countLines() { + return download(DEFAULT_URL) + .thenApply(Utility::countLines); + } + + /* + * Return a promise to provide the local absolute path of the file downloaded in background. + * This is an async method and does not wait until the file is downloaded. + */ private Promise download(String urlString) { Promise downloadPromise = new Promise() .fulfillInAsync( () -> { return Utility.downloadFile(urlString); - }, executor); - + }, executor) + .onError( + throwable -> { + throwable.printStackTrace(); + taskCompleted(); + } + ); + return downloadPromise; } private void stop() throws InterruptedException { - canStop.await(); + stopLatch.await(); executor.shutdownNow(); } - + private void taskCompleted() { - canStop.countDown(); + stopLatch.countDown(); } } diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index 7d8a97e84..870e1556d 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -36,6 +36,7 @@ import java.util.function.Function; public class Promise extends PromiseSupport { private Runnable fulfillmentAction; + private Consumer exceptionHandler; /** * Creates a promise that will be fulfilled in future. @@ -61,9 +62,17 @@ public class Promise extends PromiseSupport { @Override public void fulfillExceptionally(Exception exception) { super.fulfillExceptionally(exception); + handleException(exception); postFulfillment(); } + private void handleException(Exception exception) { + if (exceptionHandler == null) { + return; + } + exceptionHandler.accept(exception); + } + private void postFulfillment() { if (fulfillmentAction == null) { return; @@ -83,8 +92,8 @@ public class Promise extends PromiseSupport { executor.execute(() -> { try { fulfill(task.call()); - } catch (Exception e) { - fulfillExceptionally(e); + } catch (Exception ex) { + fulfillExceptionally(ex); } }); return this; @@ -96,11 +105,22 @@ public class Promise extends PromiseSupport { * @param action action to be executed. * @return a new promise. */ - public Promise then(Consumer action) { + public Promise thenAccept(Consumer action) { Promise dest = new Promise<>(); fulfillmentAction = new ConsumeAction(this, dest, action); return dest; } + + /** + * Set the exception handler on this promise. + * @param exceptionHandler a consumer that will handle the exception occurred while fulfilling + * the promise. + * @return this + */ + public Promise onError(Consumer exceptionHandler) { + this.exceptionHandler = exceptionHandler; + return this; + } /** * Returns a new promise that, when this promise is fulfilled normally, is fulfilled with @@ -108,7 +128,7 @@ public class Promise extends PromiseSupport { * @param func function to be executed. * @return a new promise. */ - public Promise then(Function func) { + public Promise thenApply(Function func) { Promise dest = new Promise<>(); fulfillmentAction = new TransformAction(this, dest, func); return dest; @@ -135,8 +155,8 @@ public class Promise extends PromiseSupport { try { action.accept(src.get()); dest.fulfill(null); - } catch (Throwable e) { - dest.fulfillExceptionally((Exception) e.getCause()); + } catch (Throwable throwable) { + dest.fulfillExceptionally((Exception) throwable.getCause()); } } } @@ -162,8 +182,8 @@ public class Promise extends PromiseSupport { try { V result = func.apply(src.get()); dest.fulfill(result); - } catch (Throwable e) { - dest.fulfillExceptionally((Exception) e.getCause()); + } catch (Throwable throwable) { + dest.fulfillExceptionally((Exception) throwable.getCause()); } } } diff --git a/promise/src/main/java/com/iluwatar/promise/Utility.java b/promise/src/main/java/com/iluwatar/promise/Utility.java index 2cfad46d0..8d5be2538 100644 --- a/promise/src/main/java/com/iluwatar/promise/Utility.java +++ b/promise/src/main/java/com/iluwatar/promise/Utility.java @@ -12,15 +12,19 @@ import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.Optional; import java.util.Map.Entry; public class Utility { + /** + * Calculates character frequency of the file provided. + * @param fileLocation location of the file. + * @return a map of character to its frequency, an empty map if file does not exist. + */ public static Map characterFrequency(String fileLocation) { Map characterToFrequency = new HashMap<>(); - try (Reader reader = new FileReader(fileLocation); - BufferedReader bufferedReader = new BufferedReader(reader);) { + try (Reader reader = new FileReader(fileLocation); + BufferedReader bufferedReader = new BufferedReader(reader)) { for (String line; (line = bufferedReader.readLine()) != null;) { for (char c : line.toCharArray()) { if (!characterToFrequency.containsKey(c)) { @@ -35,33 +39,35 @@ public class Utility { } return characterToFrequency; } - - public static Optional lowestFrequencyChar(Map charFrequency) { - Optional lowestFrequencyChar = Optional.empty(); - if (charFrequency.isEmpty()) { - return lowestFrequencyChar; - } - + + /** + * @return the character with lowest frequency if it exists, {@code Optional.empty()} otherwise. + */ + public static Character lowestFrequencyChar(Map charFrequency) { + Character lowestFrequencyChar = null; Iterator> iterator = charFrequency.entrySet().iterator(); Entry entry = iterator.next(); int minFrequency = entry.getValue(); - lowestFrequencyChar = Optional.of(entry.getKey()); - + lowestFrequencyChar = entry.getKey(); + while (iterator.hasNext()) { entry = iterator.next(); if (entry.getValue() < minFrequency) { minFrequency = entry.getValue(); - lowestFrequencyChar = Optional.of(entry.getKey()); + lowestFrequencyChar = entry.getKey(); } } - + return lowestFrequencyChar; } - + + /** + * @return number of lines in the file at provided location. 0 if file does not exist. + */ public static Integer countLines(String fileLocation) { int lineCount = 0; - try (Reader reader = new FileReader(fileLocation); - BufferedReader bufferedReader = new BufferedReader(reader);) { + try (Reader reader = new FileReader(fileLocation); + BufferedReader bufferedReader = new BufferedReader(reader)) { while (bufferedReader.readLine() != null) { lineCount++; } @@ -71,11 +77,15 @@ public class Utility { return lineCount; } + /** + * Downloads the contents from the given urlString, and stores it in a temporary directory. + * @return the absolute path of the file downloaded. + */ public static String downloadFile(String urlString) throws MalformedURLException, IOException { System.out.println("Downloading contents from url: " + urlString); URL url = new URL(urlString); File file = File.createTempFile("promise_pattern", null); - try (Reader reader = new InputStreamReader(url.openStream()); + try (Reader reader = new InputStreamReader(url.openStream()); BufferedReader bufferedReader = new BufferedReader(reader); FileWriter writer = new FileWriter(file)) { for (String line; (line = bufferedReader.readLine()) != null; ) { diff --git a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java index de0ecb6d7..45c4c1d36 100644 --- a/promise/src/test/java/com/iluwatar/promise/PromiseTest.java +++ b/promise/src/test/java/com/iluwatar/promise/PromiseTest.java @@ -26,6 +26,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -40,7 +43,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; - /** * Tests Promise class. */ @@ -73,7 +75,8 @@ public class PromiseTest { testWaitingSomeTimeForPromiseToBeFulfilled(); } - private void testWaitingForeverForPromiseToBeFulfilled() throws InterruptedException, TimeoutException { + private void testWaitingForeverForPromiseToBeFulfilled() + throws InterruptedException, TimeoutException { Promise promise = new Promise<>(); promise.fulfillInAsync(new Callable() { @@ -134,7 +137,7 @@ public class PromiseTest { throws InterruptedException, ExecutionException { Promise dependentPromise = promise .fulfillInAsync(new NumberCrunchingTask(), executor) - .then(value -> { + .thenAccept(value -> { assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value); }); @@ -149,17 +152,18 @@ public class PromiseTest { throws InterruptedException, ExecutionException, TimeoutException { Promise dependentPromise = promise .fulfillInAsync(new NumberCrunchingTask(), executor) - .then(new Consumer() { + .thenAccept(new Consumer() { @Override - public void accept(Integer t) { + public void accept(Integer value) { throw new RuntimeException("Barf!"); } }); try { dependentPromise.get(); - fail("Fetching dependent promise should result in exception if the action threw an exception"); + fail("Fetching dependent promise should result in exception " + + "if the action threw an exception"); } catch (ExecutionException ex) { assertTrue(promise.isDone()); assertFalse(promise.isCancelled()); @@ -167,7 +171,8 @@ public class PromiseTest { try { dependentPromise.get(1000, TimeUnit.SECONDS); - fail("Fetching dependent promise should result in exception if the action threw an exception"); + fail("Fetching dependent promise should result in exception " + + "if the action threw an exception"); } catch (ExecutionException ex) { assertTrue(promise.isDone()); assertFalse(promise.isCancelled()); @@ -179,7 +184,7 @@ public class PromiseTest { throws InterruptedException, ExecutionException { Promise dependentPromise = promise .fulfillInAsync(new NumberCrunchingTask(), executor) - .then(value -> { + .thenApply(value -> { assertEquals(NumberCrunchingTask.CRUNCHED_NUMBER, value); return String.valueOf(value); }); @@ -195,17 +200,18 @@ public class PromiseTest { throws InterruptedException, ExecutionException, TimeoutException { Promise dependentPromise = promise .fulfillInAsync(new NumberCrunchingTask(), executor) - .then(new Function() { + .thenApply(new Function() { @Override - public String apply(Integer t) { + public String apply(Integer value) { throw new RuntimeException("Barf!"); } }); try { dependentPromise.get(); - fail("Fetching dependent promise should result in exception if the function threw an exception"); + fail("Fetching dependent promise should result in exception " + + "if the function threw an exception"); } catch (ExecutionException ex) { assertTrue(promise.isDone()); assertFalse(promise.isCancelled()); @@ -213,7 +219,8 @@ public class PromiseTest { try { dependentPromise.get(1000, TimeUnit.SECONDS); - fail("Fetching dependent promise should result in exception if the function threw an exception"); + fail("Fetching dependent promise should result in exception " + + "if the function threw an exception"); } catch (ExecutionException ex) { assertTrue(promise.isDone()); assertFalse(promise.isCancelled()); @@ -228,6 +235,19 @@ public class PromiseTest { promise.get(1000, TimeUnit.SECONDS); } + + @SuppressWarnings("unchecked") + @Test + public void exceptionHandlerIsCalledWhenPromiseIsFulfilledExceptionally() { + Promise promise = new Promise<>(); + Consumer exceptionHandler = mock(Consumer.class); + promise.onError(exceptionHandler); + + Exception exception = new Exception("barf!"); + promise.fulfillExceptionally(exception); + + verify(exceptionHandler).accept(eq(exception)); + } private static class NumberCrunchingTask implements Callable { @@ -236,7 +256,7 @@ public class PromiseTest { @Override public Integer call() throws Exception { // Do number crunching - Thread.sleep(1000); + Thread.sleep(100); return CRUNCHED_NUMBER; } } From 5796e1967f85cd276d1b5fb311b3f1007bbcb8ae Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Mon, 29 Aug 2016 11:50:33 +0530 Subject: [PATCH 024/492] Work on #403, updated diagram and finishing touches --- promise/etc/promise.png | Bin 55725 -> 59210 bytes promise/etc/promise.ucls | 38 +++++++++--------- .../main/java/com/iluwatar/promise/App.java | 5 ++- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/promise/etc/promise.png b/promise/etc/promise.png index 0aef198acb4e9abdb4cf5b34f61869b46e870c8a..cdb43eb6b49a11b317d7c8abbb8ef3fd43ec3779 100644 GIT binary patch literal 59210 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 B1!4dI diff --git a/promise/etc/promise.ucls b/promise/etc/promise.ucls index e7fefec1c..79a11e7d5 100644 --- a/promise/etc/promise.ucls +++ b/promise/etc/promise.ucls @@ -31,7 +31,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -49,7 +49,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -67,41 +67,41 @@ - + - - - - - - - - - + - + - + - + - + - + + + + + + + + + diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 2b2ae78b4..672c20bfa 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -61,11 +61,12 @@ import java.util.concurrent.Executors; public class App { private static final String DEFAULT_URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; - private ExecutorService executor; - private CountDownLatch stopLatch = new CountDownLatch(2); + private final ExecutorService executor; + private final CountDownLatch stopLatch; private App() { executor = Executors.newFixedThreadPool(2); + stopLatch = new CountDownLatch(2); } /** From ad11ea46b11e638ee564b86eaf2e5763a3f780f1 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Mon, 29 Aug 2016 11:55:30 +0530 Subject: [PATCH 025/492] Work on #403, javadocs updated --- promise/src/main/java/com/iluwatar/promise/Promise.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index 870e1556d..3165142fa 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -29,7 +29,11 @@ import java.util.function.Consumer; import java.util.function.Function; /** - * Implements the promise pattern. + * A Promise represents a proxy for a value not necessarily known when the promise is created. It + * allows you to associate dependent promises to an asynchronous action's eventual success value or + * failure reason. This lets asynchronous methods return values like synchronous methods: instead + * of the final value, the asynchronous method returns a promise of having a value at some point + * in the future. * * @param type of result. */ From 59cf1003021f32b3e51dfaa27b7f50fb17f2c8ba Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Mon, 29 Aug 2016 12:04:24 +0530 Subject: [PATCH 026/492] #403, updated javadocs --- promise/src/main/java/com/iluwatar/promise/Promise.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/promise/src/main/java/com/iluwatar/promise/Promise.java b/promise/src/main/java/com/iluwatar/promise/Promise.java index 3165142fa..e7e56837b 100644 --- a/promise/src/main/java/com/iluwatar/promise/Promise.java +++ b/promise/src/main/java/com/iluwatar/promise/Promise.java @@ -139,7 +139,7 @@ public class Promise extends PromiseSupport { } /** - * A consume action provides the action, the value from source promise and fulfills the + * Accesses the value from source promise and calls the consumer, then fulfills the * destination promise. */ private class ConsumeAction implements Runnable { @@ -166,8 +166,8 @@ public class Promise extends PromiseSupport { } /** - * A function action provides transformation function, value from source promise and fulfills the - * destination promise with the transformed value. + * Accesses the value from source promise, then fulfills the destination promise using the + * transformed value. The source value is transformed using the transformation function. */ private class TransformAction implements Runnable { @@ -184,8 +184,7 @@ public class Promise extends PromiseSupport { @Override public void run() { try { - V result = func.apply(src.get()); - dest.fulfill(result); + dest.fulfill(func.apply(src.get())); } catch (Throwable throwable) { dest.fulfillExceptionally((Exception) throwable.getCause()); } From e73867f9a15132a8160a84eddc8da4ff5882c190 Mon Sep 17 00:00:00 2001 From: NooBxGockeL Date: Tue, 30 Aug 2016 13:24:53 +0200 Subject: [PATCH 027/492] Work on #190: Add automagic puml generation in pom.xml's --- aggregator-microservices/pom.xml | 22 +++++++++++++++++++++- api-gateway/pom.xml | 22 +++++++++++++++++++++- naked-objects/pom.xml | 19 ++++++++++++++++++- pom.xml | 27 ++++++++++++++++++++++++++- 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index 0133e9ea4..6e9496ba3 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -35,9 +35,29 @@ aggregator-microservices pom + + + + com.github.markusmo3.urm + urm-maven-plugin + ${urm.version} + + ${project.basedir}/../etc + + com.iluwatar + + + + aggregator-microservices + + + + + + information-microservice aggregator-service inventory-microservice - \ No newline at end of file + diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index 471ffda7d..48bfff9c3 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -35,9 +35,29 @@ api-gateway pom + + + + com.github.markusmo3.urm + urm-maven-plugin + ${urm.version} + + ${project.basedir}/../etc + + com.iluwatar + + + + api-gateway + + + + + + image-microservice price-microservice api-gateway-service - \ No newline at end of file + diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index b3e48dcb6..d416f2a72 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -317,6 +317,23 @@ org.apache.maven.plugins maven-surefire-report-plugin + + com.github.markusmo3.urm + urm-maven-plugin + ${urm.version} + + ${project.basedir}/../etc + + com.iluwatar + domainapp + + + + naked-objects + naked-objects-webapp + + + @@ -387,4 +404,4 @@ integtests webapp - \ No newline at end of file + diff --git a/pom.xml b/pom.xml index 6f3e0d698..80483b905 100644 --- a/pom.xml +++ b/pom.xml @@ -45,8 +45,9 @@ 1.15.1 1.10.19 4.12.1 - 4.5.2 + 4.5.2 2.22 + 1.4.0 abstract-factory @@ -422,6 +423,30 @@ + + + com.github.markusmo3.urm + urm-maven-plugin + ${urm.version} + + + process-classes + + map + + + + + ${project.basedir}/etc + + com.iluwatar + + + + java-design-patterns + + + From 36fe2499603cd103f20ffd3be9be583268415917 Mon Sep 17 00:00:00 2001 From: NooBxGockeL Date: Tue, 30 Aug 2016 13:29:12 +0200 Subject: [PATCH 028/492] Work on #190: Add first batch of automagically generated puml files --- .../etc/abstract-document.urm.puml | 59 ++++++ .../etc/abstract-factory.urm.puml | 88 +++++++++ adapter/etc/adapter.urm.puml | 35 ++++ .../etc/aggregator-service.urm.puml | 41 ++++ .../etc/information-microservice.urm.puml | 12 ++ .../etc/inventory-microservice.urm.puml | 12 ++ api-gateway/etc/api-gateway-service.urm.puml | 48 +++++ api-gateway/etc/image-microservice.urm.puml | 12 ++ api-gateway/etc/price-microservice.urm.puml | 12 ++ .../etc/async-method-invocation.urm.puml | 50 +++++ bridge/etc/bridge.urm.puml | 89 +++++++++ builder/etc/builder.urm.puml | 100 ++++++++++ .../etc/business-delegate.urm.puml | 55 ++++++ caching/etc/caching.urm.puml | 100 ++++++++++ callback/etc/callback.urm.puml | 25 +++ chain/etc/chain.urm.puml | 60 ++++++ command/etc/command.urm.puml | 84 ++++++++ composite/etc/composite.urm.puml | 42 ++++ dao/etc/dao.urm.puml | 65 +++++++ data-mapper/etc/data-mapper.urm.puml | 42 ++++ decorator/etc/decorator.urm.puml | 29 +++ delegation/etc/delegation.urm.puml | 36 ++++ .../etc/dependency-injection.urm.puml | 48 +++++ .../etc/double-checked-locking.urm.puml | 20 ++ double-dispatch/etc/double-dispatch.urm.puml | 65 +++++++ .../etc/event-aggregator.urm.puml | 73 +++++++ .../etc/event-driven-architecture.urm.puml | 62 ++++++ execute-around/etc/execute-around.urm.puml | 14 ++ facade/etc/facade.urm.puml | 57 ++++++ factory-kit/etc/factory-kit.urm.puml | 45 +++++ factory-method/etc/factory-method.urm.puml | 53 +++++ feature-toggle/etc/feature-toggle.urm.puml | 47 +++++ fluentinterface/etc/fluentinterface.urm.puml | 71 +++++++ flux/etc/flux.urm.puml | 115 +++++++++++ flyweight/etc/flyweight.urm.puml | 60 ++++++ .../etc/front-controller.urm.puml | 50 +++++ .../etc/half-sync-half-async.urm.puml | 30 +++ hexagonal/etc/hexagonal.urm.puml | 183 ++++++++++++++++++ .../etc/intercepting-filter.urm.puml | 88 +++++++++ interpreter/etc/interpreter.urm.puml | 50 +++++ iterator/etc/iterator.urm.puml | 48 +++++ layers/etc/layers.urm.puml | 125 ++++++++++++ lazy-loading/etc/lazy-loading.urm.puml | 35 ++++ mediator/etc/mediator.urm.puml | 68 +++++++ memento/etc/memento.urm.puml | 48 +++++ message-channel/etc/message-channel.urm.puml | 8 + .../etc/model-view-controller.urm.puml | 69 +++++++ .../etc/model-view-presenter.urm.puml | 87 +++++++++ monad/etc/monad.urm.puml | 35 ++++ monostate/etc/monostate.urm.puml | 32 +++ multiton/etc/multiton.urm.puml | 29 +++ mute-idiom/etc/mute-idiom.urm.puml | 23 +++ mutex/etc/mutex.urm.puml | 27 +++ naked-objects/etc/naked-objects-dom.urm.puml | 84 ++++++++ .../etc/naked-objects-fixture.urm.puml | 92 +++++++++ .../etc/naked-objects-integtests.urm.puml | 92 +++++++++ null-object/etc/null-object.urm.puml | 40 ++++ object-pool/etc/object-pool.urm.puml | 29 +++ observer/etc/observer.urm.puml | 73 +++++++ page-object/etc/page-object.urm.puml | 8 + poison-pill/etc/poison-pill.urm.puml | 72 +++++++ .../etc/private-class-data.urm.puml | 34 ++++ .../etc/producer-consumer.urm.puml | 37 ++++ property/etc/property.urm.puml | 54 ++++++ prototype/etc/prototype.urm.puml | 81 ++++++++ proxy/etc/proxy.urm.puml | 24 +++ .../etc/publish-subscribe.urm.puml | 8 + reactor/etc/reactor.urm.puml | 151 +++++++++++++++ .../etc/reader-writer-lock.urm.puml | 58 ++++++ repository/etc/repository.urm.puml | 56 ++++++ ...rce-acquisition-is-initialization.urm.puml | 16 ++ semaphore/etc/semaphore.urm.puml | 58 ++++++ servant/etc/servant.urm.puml | 55 ++++++ service-layer/etc/service-layer.urm.puml | 158 +++++++++++++++ service-locator/etc/service-locator.urm.puml | 38 ++++ singleton/etc/singleton.urm.puml | 42 ++++ specification/etc/specification.urm.puml | 106 ++++++++++ state/etc/state.urm.puml | 37 ++++ step-builder/etc/step-builder.urm.puml | 91 +++++++++ strategy/etc/strategy.urm.puml | 33 ++++ template-method/etc/template-method.urm.puml | 36 ++++ thread-pool/etc/thread-pool.urm.puml | 35 ++++ tolerant-reader/etc/tolerant-reader.urm.puml | 38 ++++ twin/etc/twin.urm.puml | 25 +++ value-object/etc/value-object.urm.puml | 21 ++ visitor/etc/visitor.urm.puml | 57 ++++++ 86 files changed, 4700 insertions(+) create mode 100644 abstract-document/etc/abstract-document.urm.puml create mode 100644 abstract-factory/etc/abstract-factory.urm.puml create mode 100644 adapter/etc/adapter.urm.puml create mode 100644 aggregator-microservices/etc/aggregator-service.urm.puml create mode 100644 aggregator-microservices/etc/information-microservice.urm.puml create mode 100644 aggregator-microservices/etc/inventory-microservice.urm.puml create mode 100644 api-gateway/etc/api-gateway-service.urm.puml create mode 100644 api-gateway/etc/image-microservice.urm.puml create mode 100644 api-gateway/etc/price-microservice.urm.puml create mode 100644 async-method-invocation/etc/async-method-invocation.urm.puml create mode 100644 bridge/etc/bridge.urm.puml create mode 100644 builder/etc/builder.urm.puml create mode 100644 business-delegate/etc/business-delegate.urm.puml create mode 100644 caching/etc/caching.urm.puml create mode 100644 callback/etc/callback.urm.puml create mode 100644 chain/etc/chain.urm.puml create mode 100644 command/etc/command.urm.puml create mode 100644 composite/etc/composite.urm.puml create mode 100644 dao/etc/dao.urm.puml create mode 100644 data-mapper/etc/data-mapper.urm.puml create mode 100644 decorator/etc/decorator.urm.puml create mode 100644 delegation/etc/delegation.urm.puml create mode 100644 dependency-injection/etc/dependency-injection.urm.puml create mode 100644 double-checked-locking/etc/double-checked-locking.urm.puml create mode 100644 double-dispatch/etc/double-dispatch.urm.puml create mode 100644 event-aggregator/etc/event-aggregator.urm.puml create mode 100644 event-driven-architecture/etc/event-driven-architecture.urm.puml create mode 100644 execute-around/etc/execute-around.urm.puml create mode 100644 facade/etc/facade.urm.puml create mode 100644 factory-kit/etc/factory-kit.urm.puml create mode 100644 factory-method/etc/factory-method.urm.puml create mode 100644 feature-toggle/etc/feature-toggle.urm.puml create mode 100644 fluentinterface/etc/fluentinterface.urm.puml create mode 100644 flux/etc/flux.urm.puml create mode 100644 flyweight/etc/flyweight.urm.puml create mode 100644 front-controller/etc/front-controller.urm.puml create mode 100644 half-sync-half-async/etc/half-sync-half-async.urm.puml create mode 100644 hexagonal/etc/hexagonal.urm.puml create mode 100644 intercepting-filter/etc/intercepting-filter.urm.puml create mode 100644 interpreter/etc/interpreter.urm.puml create mode 100644 iterator/etc/iterator.urm.puml create mode 100644 layers/etc/layers.urm.puml create mode 100644 lazy-loading/etc/lazy-loading.urm.puml create mode 100644 mediator/etc/mediator.urm.puml create mode 100644 memento/etc/memento.urm.puml create mode 100644 message-channel/etc/message-channel.urm.puml create mode 100644 model-view-controller/etc/model-view-controller.urm.puml create mode 100644 model-view-presenter/etc/model-view-presenter.urm.puml create mode 100644 monad/etc/monad.urm.puml create mode 100644 monostate/etc/monostate.urm.puml create mode 100644 multiton/etc/multiton.urm.puml create mode 100644 mute-idiom/etc/mute-idiom.urm.puml create mode 100644 mutex/etc/mutex.urm.puml create mode 100644 naked-objects/etc/naked-objects-dom.urm.puml create mode 100644 naked-objects/etc/naked-objects-fixture.urm.puml create mode 100644 naked-objects/etc/naked-objects-integtests.urm.puml create mode 100644 null-object/etc/null-object.urm.puml create mode 100644 object-pool/etc/object-pool.urm.puml create mode 100644 observer/etc/observer.urm.puml create mode 100644 page-object/etc/page-object.urm.puml create mode 100644 poison-pill/etc/poison-pill.urm.puml create mode 100644 private-class-data/etc/private-class-data.urm.puml create mode 100644 producer-consumer/etc/producer-consumer.urm.puml create mode 100644 property/etc/property.urm.puml create mode 100644 prototype/etc/prototype.urm.puml create mode 100644 proxy/etc/proxy.urm.puml create mode 100644 publish-subscribe/etc/publish-subscribe.urm.puml create mode 100644 reactor/etc/reactor.urm.puml create mode 100644 reader-writer-lock/etc/reader-writer-lock.urm.puml create mode 100644 repository/etc/repository.urm.puml create mode 100644 resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml create mode 100644 semaphore/etc/semaphore.urm.puml create mode 100644 servant/etc/servant.urm.puml create mode 100644 service-layer/etc/service-layer.urm.puml create mode 100644 service-locator/etc/service-locator.urm.puml create mode 100644 singleton/etc/singleton.urm.puml create mode 100644 specification/etc/specification.urm.puml create mode 100644 state/etc/state.urm.puml create mode 100644 step-builder/etc/step-builder.urm.puml create mode 100644 strategy/etc/strategy.urm.puml create mode 100644 template-method/etc/template-method.urm.puml create mode 100644 thread-pool/etc/thread-pool.urm.puml create mode 100644 tolerant-reader/etc/tolerant-reader.urm.puml create mode 100644 twin/etc/twin.urm.puml create mode 100644 value-object/etc/value-object.urm.puml create mode 100644 visitor/etc/visitor.urm.puml diff --git a/abstract-document/etc/abstract-document.urm.puml b/abstract-document/etc/abstract-document.urm.puml new file mode 100644 index 000000000..c738b50ce --- /dev/null +++ b/abstract-document/etc/abstract-document.urm.puml @@ -0,0 +1,59 @@ +@startuml +package com.iluwatar.abstractdocument.domain { + class Part { + + Part(properties : Map) + } + class Car { + + Car(properties : Map) + } + interface HasModel { + + PROPERTY : String {static} + + getModel() : Optional + } + interface HasParts { + + PROPERTY : String {static} + + getParts() : Stream + } + interface HasType { + + PROPERTY : String {static} + + getType() : Optional + } + interface HasPrice { + + PROPERTY : String {static} + + getPrice() : Optional + } +} +package com.iluwatar.abstractdocument { + interface Document { + + children(String, Function, T>) : Stream {abstract} + + get(String) : Object {abstract} + + put(String, Object) {abstract} + } + abstract class AbstractDocument { + - properties : Map + # AbstractDocument(properties : Map) + + children(key : String, constructor : Function, T>) : Stream + + get(key : String) : Object + + put(key : String, value : Object) + + toString() : String + } + class App { + + App() + + main(args : String[]) {static} + } +} +AbstractDocument --+ Map +Part ..|> HasType +Part ..|> HasModel +Part ..|> HasPrice +Part --|> AbstractDocument +Car ..|> HasModel +Car ..|> HasPrice +Car ..|> HasParts +Car --|> AbstractDocument +HasModel --|> Document +HasParts --|> Document +AbstractDocument ..|> Document +HasType --|> Document +HasPrice --|> Document +@enduml \ No newline at end of file diff --git a/abstract-factory/etc/abstract-factory.urm.puml b/abstract-factory/etc/abstract-factory.urm.puml new file mode 100644 index 000000000..88402c6d7 --- /dev/null +++ b/abstract-factory/etc/abstract-factory.urm.puml @@ -0,0 +1,88 @@ +@startuml +package com.iluwatar.abstractfactory { + interface Castle { + + getDescription() : String {abstract} + } + class OrcKingdomFactory { + + OrcKingdomFactory() + + createArmy() : Army + + createCastle() : Castle + + createKing() : King + } + class ElfKing { + ~ DESCRIPTION : String {static} + + ElfKing() + + getDescription() : String + } + interface King { + + getDescription() : String {abstract} + } + class App { + - army : Army + - castle : Castle + - king : King + + App() + + createKingdom(factory : KingdomFactory) + + getArmy() : Army + ~ getArmy(factory : KingdomFactory) : Army + + getCastle() : Castle + ~ getCastle(factory : KingdomFactory) : Castle + + getKing() : King + ~ getKing(factory : KingdomFactory) : King + + main(args : String[]) {static} + - setArmy(army : Army) + - setCastle(castle : Castle) + - setKing(king : King) + } + class OrcKing { + ~ DESCRIPTION : String {static} + + OrcKing() + + getDescription() : String + } + class ElfKingdomFactory { + + ElfKingdomFactory() + + createArmy() : Army + + createCastle() : Castle + + createKing() : King + } + interface Army { + + getDescription() : String {abstract} + } + class OrcArmy { + ~ DESCRIPTION : String {static} + + OrcArmy() + + getDescription() : String + } + interface KingdomFactory { + + createArmy() : Army {abstract} + + createCastle() : Castle {abstract} + + createKing() : King {abstract} + } + class ElfArmy { + ~ DESCRIPTION : String {static} + + ElfArmy() + + getDescription() : String + } + class ElfCastle { + ~ DESCRIPTION : String {static} + + ElfCastle() + + getDescription() : String + } + class OrcCastle { + ~ DESCRIPTION : String {static} + + OrcCastle() + + getDescription() : String + } +} +App --> "-castle" Castle +App --> "-king" King +App --> "-army" Army +OrcKingdomFactory ..|> KingdomFactory +ElfKing ..|> King +OrcKing ..|> King +ElfKingdomFactory ..|> KingdomFactory +OrcArmy ..|> Army +ElfArmy ..|> Army +ElfCastle ..|> Castle +OrcCastle ..|> Castle +@enduml \ No newline at end of file diff --git a/adapter/etc/adapter.urm.puml b/adapter/etc/adapter.urm.puml new file mode 100644 index 000000000..2cee13dc4 --- /dev/null +++ b/adapter/etc/adapter.urm.puml @@ -0,0 +1,35 @@ +@startuml +package com.iluwatar.adapter { + class App { + + App() + + main(args : String[]) {static} + } + interface BattleShip { + + fire() {abstract} + + move() {abstract} + } + class Captain { + - battleship : BattleShip + + Captain() + + Captain(battleship : BattleShip) + + fire() + + move() + + setBattleship(battleship : BattleShip) + } + class BattleFishingBoat { + - boat : FishingBoat + + BattleFishingBoat() + + fire() + + move() + } + class FishingBoat { + + FishingBoat() + + fish() + + sail() + } +} +BattleFishingBoat --> "-boat" FishingBoat +Captain --> "-battleship" BattleShip +Captain ..|> BattleShip +BattleFishingBoat ..|> BattleShip +@enduml \ No newline at end of file diff --git a/aggregator-microservices/etc/aggregator-service.urm.puml b/aggregator-microservices/etc/aggregator-service.urm.puml new file mode 100644 index 000000000..5c2e1167a --- /dev/null +++ b/aggregator-microservices/etc/aggregator-service.urm.puml @@ -0,0 +1,41 @@ +@startuml +package com.iluwatar.aggregator.microservices { + class Aggregator { + - informationClient : ProductInformationClient + - inventoryClient : ProductInventoryClient + + Aggregator() + + getProduct() : Product + } + class ProductInformationClientImpl { + + ProductInformationClientImpl() + + getProductTitle() : String + } + interface ProductInformationClient { + + getProductTitle() : String {abstract} + } + class Product { + - productInventories : int + - title : String + + Product() + + getProductInventories() : int + + getTitle() : String + + setProductInventories(productInventories : int) + + setTitle(title : String) + } + class ProductInventoryClientImpl { + + ProductInventoryClientImpl() + + getProductInventories() : int + } + class App { + + App() + + main(args : String[]) {static} + } + interface ProductInventoryClient { + + getProductInventories() : int {abstract} + } +} +Aggregator --> "-inventoryClient" ProductInventoryClient +Aggregator --> "-informationClient" ProductInformationClient +ProductInformationClientImpl ..|> ProductInformationClient +ProductInventoryClientImpl ..|> ProductInventoryClient +@enduml \ No newline at end of file diff --git a/aggregator-microservices/etc/information-microservice.urm.puml b/aggregator-microservices/etc/information-microservice.urm.puml new file mode 100644 index 000000000..e0a2ccb24 --- /dev/null +++ b/aggregator-microservices/etc/information-microservice.urm.puml @@ -0,0 +1,12 @@ +@startuml +package com.iluwatar.information.microservice { + class InformationApplication { + + InformationApplication() + + main(args : String[]) {static} + } + class InformationController { + + InformationController() + + getProductTitle() : String + } +} +@enduml \ No newline at end of file diff --git a/aggregator-microservices/etc/inventory-microservice.urm.puml b/aggregator-microservices/etc/inventory-microservice.urm.puml new file mode 100644 index 000000000..90f327e07 --- /dev/null +++ b/aggregator-microservices/etc/inventory-microservice.urm.puml @@ -0,0 +1,12 @@ +@startuml +package com.iluwatar.inventory.microservice { + class InventoryApplication { + + InventoryApplication() + + main(args : String[]) {static} + } + class InventoryController { + + InventoryController() + + getProductInventories() : int + } +} +@enduml \ No newline at end of file diff --git a/api-gateway/etc/api-gateway-service.urm.puml b/api-gateway/etc/api-gateway-service.urm.puml new file mode 100644 index 000000000..3313f7059 --- /dev/null +++ b/api-gateway/etc/api-gateway-service.urm.puml @@ -0,0 +1,48 @@ +@startuml +package com.iluwatar.api.gateway { + interface ImageClient { + + getImagePath() : String {abstract} + } + class MobileProduct { + - price : String + + MobileProduct() + + getPrice() : String + + setPrice(price : String) + } + class ApiGateway { + - imageClient : ImageClient + - priceClient : PriceClient + + ApiGateway() + + getProductDesktop() : DesktopProduct + + getProductMobile() : MobileProduct + } + class DesktopProduct { + - imagePath : String + - price : String + + DesktopProduct() + + getImagePath() : String + + getPrice() : String + + setImagePath(imagePath : String) + + setPrice(price : String) + } + interface PriceClient { + + getPrice() : String {abstract} + } + class PriceClientImpl { + + PriceClientImpl() + + getPrice() : String + } + class ImageClientImpl { + + ImageClientImpl() + + getImagePath() : String + } + class App { + + App() + + main(args : String[]) {static} + } +} +ApiGateway --> "-imageClient" ImageClient +ApiGateway --> "-priceClient" PriceClient +PriceClientImpl ..|> PriceClient +ImageClientImpl ..|> ImageClient +@enduml \ No newline at end of file diff --git a/api-gateway/etc/image-microservice.urm.puml b/api-gateway/etc/image-microservice.urm.puml new file mode 100644 index 000000000..130dac9de --- /dev/null +++ b/api-gateway/etc/image-microservice.urm.puml @@ -0,0 +1,12 @@ +@startuml +package com.iluwatar.image.microservice { + class ImageApplication { + + ImageApplication() + + main(args : String[]) {static} + } + class ImageController { + + ImageController() + + getImagePath() : String + } +} +@enduml \ No newline at end of file diff --git a/api-gateway/etc/price-microservice.urm.puml b/api-gateway/etc/price-microservice.urm.puml new file mode 100644 index 000000000..9893c9c60 --- /dev/null +++ b/api-gateway/etc/price-microservice.urm.puml @@ -0,0 +1,12 @@ +@startuml +package com.iluwatar.price.microservice { + class PriceApplication { + + PriceApplication() + + main(args : String[]) {static} + } + class PriceController { + + PriceController() + + getPrice() : String + } +} +@enduml \ No newline at end of file diff --git a/async-method-invocation/etc/async-method-invocation.urm.puml b/async-method-invocation/etc/async-method-invocation.urm.puml new file mode 100644 index 000000000..9a90d307e --- /dev/null +++ b/async-method-invocation/etc/async-method-invocation.urm.puml @@ -0,0 +1,50 @@ +@startuml +package com.iluwatar.async.method.invocation { + interface AsyncCallback { + + onComplete(T, Optional) {abstract} + } + interface AsyncResult { + + await() {abstract} + + getValue() : T {abstract} + + isCompleted() : boolean {abstract} + } + class ThreadAsyncExecutor { + - idx : AtomicInteger + + ThreadAsyncExecutor() + + endProcess(asyncResult : AsyncResult) : T + + startProcess(task : Callable) : AsyncResult + + startProcess(task : Callable, callback : AsyncCallback) : AsyncResult + } + class App { + + App() + - callback(name : String) : AsyncCallback {static} + - lazyval(value : T, delayMillis : long) : Callable {static} + - log(msg : String) {static} + + main(args : String[]) {static} + } + -class CompletableResult { + ~ COMPLETED : int {static} + ~ FAILED : int {static} + ~ RUNNING : int {static} + ~ callback : Optional> + ~ exception : Exception + ~ lock : Object + ~ state : int + ~ value : T + ~ CompletableResult(callback : AsyncCallback) + + await() + + getValue() : T + + isCompleted() : boolean + ~ setException(exception : Exception) + ~ setValue(value : T) + } + interface AsyncExecutor { + + endProcess(AsyncResult) : T {abstract} + + startProcess(Callable) : AsyncResult {abstract} + + startProcess(Callable, AsyncCallback) : AsyncResult {abstract} + } +} +CompletableResult ..+ ThreadAsyncExecutor +ThreadAsyncExecutor ..|> AsyncExecutor +CompletableResult ..|> AsyncResult +@enduml \ No newline at end of file diff --git a/bridge/etc/bridge.urm.puml b/bridge/etc/bridge.urm.puml new file mode 100644 index 000000000..d9d7a4145 --- /dev/null +++ b/bridge/etc/bridge.urm.puml @@ -0,0 +1,89 @@ +@startuml +package com.iluwatar.bridge { + class FlyingMagicWeapon { + + FlyingMagicWeapon(imp : FlyingMagicWeaponImpl) + + fly() + + getImp() : FlyingMagicWeaponImpl + + swing() + + unwield() + + wield() + } + abstract class MagicWeapon { + # imp : MagicWeaponImpl + + MagicWeapon(imp : MagicWeaponImpl) + + getImp() : MagicWeaponImpl + + swing() {abstract} + + unwield() {abstract} + + wield() {abstract} + } + abstract class SoulEatingMagicWeaponImpl { + + SoulEatingMagicWeaponImpl() + + eatSoulImp() {abstract} + } + class BlindingMagicWeapon { + + BlindingMagicWeapon(imp : BlindingMagicWeaponImpl) + + blind() + + getImp() : BlindingMagicWeaponImpl + + swing() + + unwield() + + wield() + } + class Stormbringer { + + Stormbringer() + + eatSoulImp() + + swingImp() + + unwieldImp() + + wieldImp() + } + abstract class BlindingMagicWeaponImpl { + + BlindingMagicWeaponImpl() + + blindImp() {abstract} + } + class SoulEatingMagicWeapon { + + SoulEatingMagicWeapon(imp : SoulEatingMagicWeaponImpl) + + eatSoul() + + getImp() : SoulEatingMagicWeaponImpl + + swing() + + unwield() + + wield() + } + abstract class MagicWeaponImpl { + + MagicWeaponImpl() + + swingImp() {abstract} + + unwieldImp() {abstract} + + wieldImp() {abstract} + } + class Excalibur { + + Excalibur() + + blindImp() + + swingImp() + + unwieldImp() + + wieldImp() + } + abstract class FlyingMagicWeaponImpl { + + FlyingMagicWeaponImpl() + + flyImp() {abstract} + } + class Mjollnir { + + Mjollnir() + + flyImp() + + swingImp() + + unwieldImp() + + wieldImp() + } + class App { + + App() + + main(args : String[]) {static} + } +} +MagicWeapon --> "-imp" MagicWeaponImpl +FlyingMagicWeapon --|> MagicWeapon +SoulEatingMagicWeaponImpl --|> MagicWeaponImpl +BlindingMagicWeapon --|> MagicWeapon +Stormbringer --|> SoulEatingMagicWeaponImpl +BlindingMagicWeaponImpl --|> MagicWeaponImpl +SoulEatingMagicWeapon --|> MagicWeapon +Excalibur --|> BlindingMagicWeaponImpl +FlyingMagicWeaponImpl --|> MagicWeaponImpl +Mjollnir --|> FlyingMagicWeaponImpl +@enduml \ No newline at end of file diff --git a/builder/etc/builder.urm.puml b/builder/etc/builder.urm.puml new file mode 100644 index 000000000..262476329 --- /dev/null +++ b/builder/etc/builder.urm.puml @@ -0,0 +1,100 @@ +@startuml +package com.iluwatar.builder { + class Hero { + - armor : Armor + - hairColor : HairColor + - hairType : HairType + - name : String + - profession : Profession + - weapon : Weapon + - Hero(builder : Builder) + + getArmor() : Armor + + getHairColor() : HairColor + + getHairType() : HairType + + getName() : String + + getProfession() : Profession + + getWeapon() : Weapon + + toString() : String + } + class App { + + App() + + main(args : String[]) {static} + } + class Builder { + - armor : Armor + - hairColor : HairColor + - hairType : HairType + - name : String + - profession : Profession + - weapon : Weapon + + Builder(profession : Profession, name : String) + + build() : Hero + + withArmor(armor : Armor) : Builder + + withHairColor(hairColor : HairColor) : Builder + + withHairType(hairType : HairType) : Builder + + withWeapon(weapon : Weapon) : Builder + } + enum Armor { + + CHAIN_MAIL {static} + + CLOTHES {static} + + LEATHER {static} + + PLATE_MAIL {static} + - title : String + + toString() : String + + valueOf(name : String) : Armor {static} + + values() : Armor[] {static} + } + enum Profession { + + MAGE {static} + + PRIEST {static} + + THIEF {static} + + WARRIOR {static} + + toString() : String + + valueOf(name : String) : Profession {static} + + values() : Profession[] {static} + } + enum Weapon { + + AXE {static} + + BOW {static} + + DAGGER {static} + + SWORD {static} + + WARHAMMER {static} + + toString() : String + + valueOf(name : String) : Weapon {static} + + values() : Weapon[] {static} + } + enum HairType { + + BALD {static} + + CURLY {static} + + LONG_CURLY {static} + + LONG_STRAIGHT {static} + + SHORT {static} + - title : String + + toString() : String + + valueOf(name : String) : HairType {static} + + values() : HairType[] {static} + } + enum HairColor { + + BLACK {static} + + BLOND {static} + + BROWN {static} + + RED {static} + + WHITE {static} + + toString() : String + + valueOf(name : String) : HairColor {static} + + values() : HairColor[] {static} + } +} +Builder ..+ Hero +Hero --> "-profession" Profession +Hero --> "-armor" Armor +App --+ Hero +Builder --> "-weapon" Weapon +Builder --> "-hairColor" HairColor +Builder --> "-hairType" HairType +Hero --> "-hairColor" HairColor +Builder --> "-profession" Profession +Hero --> "-weapon" Weapon +Hero --> "-hairType" HairType +Builder --> "-armor" Armor +@enduml \ No newline at end of file diff --git a/business-delegate/etc/business-delegate.urm.puml b/business-delegate/etc/business-delegate.urm.puml new file mode 100644 index 000000000..a8f31700b --- /dev/null +++ b/business-delegate/etc/business-delegate.urm.puml @@ -0,0 +1,55 @@ +@startuml +package com.iluwatar.business.delegate { + class BusinessLookup { + - ejbService : EjbService + - jmsService : JmsService + + BusinessLookup() + + getBusinessService(serviceType : ServiceType) : BusinessService + + setEjbService(ejbService : EjbService) + + setJmsService(jmsService : JmsService) + } + class Client { + - businessDelegate : BusinessDelegate + + Client(businessDelegate : BusinessDelegate) + + doTask() + } + class EjbService { + + EjbService() + + doProcessing() + } + class BusinessDelegate { + - businessService : BusinessService + - lookupService : BusinessLookup + - serviceType : ServiceType + + BusinessDelegate() + + doTask() + + setLookupService(businessLookup : BusinessLookup) + + setServiceType(serviceType : ServiceType) + } + interface BusinessService { + + doProcessing() {abstract} + } + class JmsService { + + JmsService() + + doProcessing() + } + class App { + + App() + + main(args : String[]) {static} + } + enum ServiceType { + + EJB {static} + + JMS {static} + + valueOf(name : String) : ServiceType {static} + + values() : ServiceType[] {static} + } +} +BusinessDelegate --> "-serviceType" ServiceType +BusinessLookup --> "-ejbService" EjbService +Client --> "-businessDelegate" BusinessDelegate +BusinessDelegate --> "-businessService" BusinessService +BusinessDelegate --> "-lookupService" BusinessLookup +BusinessLookup --> "-jmsService" JmsService +EjbService ..|> BusinessService +JmsService ..|> BusinessService +@enduml \ No newline at end of file diff --git a/caching/etc/caching.urm.puml b/caching/etc/caching.urm.puml new file mode 100644 index 000000000..273c9911c --- /dev/null +++ b/caching/etc/caching.urm.puml @@ -0,0 +1,100 @@ +@startuml +package com.iluwatar.caching { + class UserAccount { + - additionalInfo : String + - userId : String + - userName : String + + UserAccount(userId : String, userName : String, additionalInfo : String) + + getAdditionalInfo() : String + + getUserId() : String + + getUserName() : String + + setAdditionalInfo(additionalInfo : String) + + setUserId(userId : String) + + setUserName(userName : String) + + toString() : String + } + class CacheStore { + ~ cache : LruCache {static} + - CacheStore() + + clearCache() {static} + + flushCache() {static} + + initCapacity(capacity : int) {static} + + print() : String {static} + + readThrough(userId : String) : UserAccount {static} + + readThroughWithWriteBackPolicy(userId : String) : UserAccount {static} + + writeAround(userAccount : UserAccount) {static} + + writeBehind(userAccount : UserAccount) {static} + + writeThrough(userAccount : UserAccount) {static} + } + class AppManager { + - cachingPolicy : CachingPolicy {static} + - AppManager() + + find(userId : String) : UserAccount {static} + + initCacheCapacity(capacity : int) {static} + + initCachingPolicy(policy : CachingPolicy) {static} + + initDb(useMongoDb : boolean) {static} + + printCacheContent() : String {static} + + save(userAccount : UserAccount) {static} + } + ~class Node { + ~ next : Node + ~ previous : Node + ~ userAccount : UserAccount + ~ userId : String + + Node(this$0 : LruCache, userId : String, userAccount : UserAccount) + } + class LruCache { + ~ cache : Map + ~ capacity : int + ~ end : Node + ~ head : Node + + LruCache(capacity : int) + + clear() + + contains(userId : String) : boolean + + get(userId : String) : UserAccount + + getCacheDataInListForm() : List + + getLruData() : UserAccount + + invalidate(userId : String) + + isFull() : boolean + + remove(node : Node) + + set(userId : String, userAccount : UserAccount) + + setCapacity(newCapacity : int) + + setHead(node : Node) + } + class DbManager { + - db : MongoDatabase {static} + - mongoClient : MongoClient {static} + - useMongoDB : boolean {static} + - virtualDB : Map {static} + - DbManager() + + connect() {static} + + createVirtualDb() {static} + + readFromDb(userId : String) : UserAccount {static} + + updateDb(userAccount : UserAccount) {static} + + upsertDb(userAccount : UserAccount) {static} + + writeToDb(userAccount : UserAccount) {static} + } + class App { + + App() + + main(args : String[]) {static} + + useReadAndWriteThroughStrategy() + + useReadThroughAndWriteAroundStrategy() + + useReadThroughAndWriteBehindStrategy() + } + enum CachingPolicy { + + AROUND {static} + + BEHIND {static} + + THROUGH {static} + - policy : String + + getPolicy() : String + + valueOf(name : String) : CachingPolicy {static} + + values() : CachingPolicy[] {static} + } +} +Node --+ LruCache +LruCache --> "-head" Node +Node --> "-previous" Node +AppManager --> "-cachingPolicy" CachingPolicy +Node --> "-userAccount" UserAccount +CacheStore --> "-cache" LruCache +@enduml \ No newline at end of file diff --git a/callback/etc/callback.urm.puml b/callback/etc/callback.urm.puml new file mode 100644 index 000000000..8b27ee8a8 --- /dev/null +++ b/callback/etc/callback.urm.puml @@ -0,0 +1,25 @@ +@startuml +package com.iluwatar.callback { + class LambdasApp { + + LambdasApp() + + main(args : String[]) {static} + } + class SimpleTask { + + SimpleTask() + + execute() + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class Task { + + Task() + + execute() {abstract} + + executeWith(callback : Callback) + } + interface Callback { + + call() {abstract} + } +} +SimpleTask --|> Task +@enduml \ No newline at end of file diff --git a/chain/etc/chain.urm.puml b/chain/etc/chain.urm.puml new file mode 100644 index 000000000..c75cbc8d1 --- /dev/null +++ b/chain/etc/chain.urm.puml @@ -0,0 +1,60 @@ +@startuml +package com.iluwatar.chain { + class OrcCommander { + + OrcCommander(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } + class App { + + App() + + main(args : String[]) {static} + } + class Request { + - handled : boolean + - requestDescription : String + - requestType : RequestType + + Request(requestType : RequestType, requestDescription : String) + + getRequestDescription() : String + + getRequestType() : RequestType + + isHandled() : boolean + + markHandled() + + toString() : String + } + class OrcOfficer { + + OrcOfficer(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } + class OrcKing { + ~ chain : RequestHandler + + OrcKing() + - buildChain() + + makeRequest(req : Request) + } + class OrcSoldier { + + OrcSoldier(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } + abstract class RequestHandler { + - next : RequestHandler + + RequestHandler(next : RequestHandler) + + handleRequest(req : Request) + # printHandling(req : Request) + + toString() : String {abstract} + } + enum RequestType { + + COLLECT_TAX {static} + + DEFEND_CASTLE {static} + + TORTURE_PRISONER {static} + + valueOf(name : String) : RequestType {static} + + values() : RequestType[] {static} + } +} +RequestHandler --> "-next" RequestHandler +OrcKing --> "-chain" RequestHandler +Request --> "-requestType" RequestType +OrcCommander --|> RequestHandler +OrcOfficer --|> RequestHandler +OrcSoldier --|> RequestHandler +@enduml \ No newline at end of file diff --git a/command/etc/command.urm.puml b/command/etc/command.urm.puml new file mode 100644 index 000000000..015fb30be --- /dev/null +++ b/command/etc/command.urm.puml @@ -0,0 +1,84 @@ +@startuml +package com.iluwatar.command { + abstract class Target { + - size : Size + - visibility : Visibility + + Target() + + getSize() : Size + + getVisibility() : Visibility + + printStatus() + + setSize(size : Size) + + setVisibility(visibility : Visibility) + + toString() : String {abstract} + } + class Goblin { + + Goblin() + + toString() : String + } + class ShrinkSpell { + - oldSize : Size + - target : Target + + ShrinkSpell() + + execute(target : Target) + + redo() + + toString() : String + + undo() + } + class InvisibilitySpell { + - target : Target + + InvisibilitySpell() + + execute(target : Target) + + redo() + + toString() : String + + undo() + } + class Wizard { + - redoStack : Deque + - undoStack : Deque + + Wizard() + + castSpell(command : Command, target : Target) + + redoLastSpell() + + toString() : String + + undoLastSpell() + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class Command { + + Command() + + execute(Target) {abstract} + + redo() {abstract} + + toString() : String {abstract} + + undo() {abstract} + } + enum Size { + + LARGE {static} + + NORMAL {static} + + SMALL {static} + + UNDEFINED {static} + - title : String + + toString() : String + + valueOf(name : String) : Size {static} + + values() : Size[] {static} + } + enum Visibility { + + INVISIBLE {static} + + UNDEFINED {static} + + VISIBLE {static} + - title : String + + toString() : String + + valueOf(name : String) : Visibility {static} + + values() : Visibility[] {static} + } +} +Target --> "-size" Size +Wizard --> "-undoStack" Command +ShrinkSpell --> "-oldSize" Size +InvisibilitySpell --> "-target" Target +ShrinkSpell --> "-target" Target +Target --> "-visibility" Visibility +Goblin --|> Target +ShrinkSpell --|> Command +InvisibilitySpell --|> Command +@enduml \ No newline at end of file diff --git a/composite/etc/composite.urm.puml b/composite/etc/composite.urm.puml new file mode 100644 index 000000000..6f6e93c98 --- /dev/null +++ b/composite/etc/composite.urm.puml @@ -0,0 +1,42 @@ +@startuml +package com.iluwatar.composite { + class Letter { + - c : char + + Letter(c : char) + # printThisAfter() + # printThisBefore() + } + class Sentence { + + Sentence(words : List) + # printThisAfter() + # printThisBefore() + } + class Word { + + Word(letters : List) + # printThisAfter() + # printThisBefore() + } + class Messenger { + + Messenger() + ~ messageFromElves() : LetterComposite + ~ messageFromOrcs() : LetterComposite + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class LetterComposite { + - children : List + + LetterComposite() + + add(letter : LetterComposite) + + count() : int + + print() + # printThisAfter() {abstract} + # printThisBefore() {abstract} + } +} +LetterComposite --> "-children" LetterComposite +Letter --|> LetterComposite +Sentence --|> LetterComposite +Word --|> LetterComposite +@enduml \ No newline at end of file diff --git a/dao/etc/dao.urm.puml b/dao/etc/dao.urm.puml new file mode 100644 index 000000000..f751b967c --- /dev/null +++ b/dao/etc/dao.urm.puml @@ -0,0 +1,65 @@ +@startuml +package com.iluwatar.dao { + class Customer { + - firstName : String + - id : int + - lastName : String + + Customer(id : int, firstName : String, lastName : String) + + equals(that : 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 DbCustomerDao { + - 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) + + 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 + } + interface CustomerSchemaSql { + + CREATE_SCHEMA_SQL : String {static} + + DELETE_SCHEMA_SQL : String {static} + } + class App { + - DB_URL : String {static} + - log : 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} + } +} +DbCustomerDao ..|> CustomerDao +InMemoryCustomerDao ..|> CustomerDao +@enduml \ No newline at end of file diff --git a/data-mapper/etc/data-mapper.urm.puml b/data-mapper/etc/data-mapper.urm.puml new file mode 100644 index 000000000..a16df0020 --- /dev/null +++ b/data-mapper/etc/data-mapper.urm.puml @@ -0,0 +1,42 @@ +@startuml +package com.iluwatar.datamapper { + interface StudentDataMapper { + + delete(Student) {abstract} + + find(int) : Optional {abstract} + + insert(Student) {abstract} + + update(Student) {abstract} + } + class App { + - log : Logger {static} + - App() + + main(args : String[]) {static} + } + class Student { + - grade : char + - name : String + - serialVersionUID : long {static} + - studentId : int + + Student(studentId : int, name : String, grade : char) + + equals(inputObject : Object) : boolean + + getGrade() : char + + getName() : String + + getStudentId() : int + + hashCode() : int + + setGrade(grade : char) + + setName(name : String) + + setStudentId(studentId : int) + + toString() : String + } + class StudentDataMapperImpl { + - students : List + + StudentDataMapperImpl() + + delete(studentToBeDeleted : Student) + + find(studentId : int) : Optional + + getStudents() : List + + insert(studentToBeInserted : Student) + + update(studentToBeUpdated : Student) + } +} +StudentDataMapperImpl --> "-students" Student +StudentDataMapperImpl ..|> StudentDataMapper +@enduml \ No newline at end of file diff --git a/decorator/etc/decorator.urm.puml b/decorator/etc/decorator.urm.puml new file mode 100644 index 000000000..6c44e6cc9 --- /dev/null +++ b/decorator/etc/decorator.urm.puml @@ -0,0 +1,29 @@ +@startuml +package com.iluwatar.decorator { + class App { + + App() + + main(args : String[]) {static} + } + class Troll { + + Troll() + + attack() + + fleeBattle() + + getAttackPower() : int + } + interface Hostile { + + attack() {abstract} + + fleeBattle() {abstract} + + getAttackPower() : int {abstract} + } + class SmartHostile { + - decorated : Hostile + + SmartHostile(decorated : Hostile) + + attack() + + fleeBattle() + + getAttackPower() : int + } +} +SmartHostile --> "-decorated" Hostile +Troll ..|> Hostile +SmartHostile ..|> Hostile +@enduml \ No newline at end of file diff --git a/delegation/etc/delegation.urm.puml b/delegation/etc/delegation.urm.puml new file mode 100644 index 000000000..c143a6ba0 --- /dev/null +++ b/delegation/etc/delegation.urm.puml @@ -0,0 +1,36 @@ +@startuml +package com.iluwatar.delegation.simple.printers { + class EpsonPrinter { + + EpsonPrinter() + + print(message : String) + } + class HpPrinter { + + HpPrinter() + + print(message : String) + } + class CanonPrinter { + + CanonPrinter() + + print(message : String) + } +} +package com.iluwatar.delegation.simple { + class PrinterController { + - printer : Printer + + PrinterController(printer : Printer) + + print(message : String) + } + interface Printer { + + print(String) {abstract} + } + class App { + + MESSAGE_TO_PRINT : String {static} + + App() + + main(args : String[]) {static} + } +} +PrinterController --> "-printer" Printer +PrinterController ..|> Printer +EpsonPrinter ..|> Printer +HpPrinter ..|> Printer +CanonPrinter ..|> Printer +@enduml \ No newline at end of file diff --git a/dependency-injection/etc/dependency-injection.urm.puml b/dependency-injection/etc/dependency-injection.urm.puml new file mode 100644 index 000000000..c22c658ad --- /dev/null +++ b/dependency-injection/etc/dependency-injection.urm.puml @@ -0,0 +1,48 @@ +@startuml +package com.iluwatar.dependency.injection { + interface Wizard { + + smoke() {abstract} + } + class GuiceWizard { + - tobacco : Tobacco + + GuiceWizard(tobacco : Tobacco) + + smoke() + } + class OldTobyTobacco { + + OldTobyTobacco() + } + abstract class Tobacco { + + Tobacco() + + smoke(wizard : Wizard) + } + class App { + + App() + + main(args : String[]) {static} + } + class RivendellTobacco { + + RivendellTobacco() + } + class AdvancedWizard { + - tobacco : Tobacco + + AdvancedWizard(tobacco : Tobacco) + + smoke() + } + class SecondBreakfastTobacco { + + SecondBreakfastTobacco() + } + class SimpleWizard { + - tobacco : OldTobyTobacco + + SimpleWizard() + + smoke() + } +} +SimpleWizard --> "-tobacco" OldTobyTobacco +AdvancedWizard --> "-tobacco" Tobacco +GuiceWizard --> "-tobacco" Tobacco +GuiceWizard ..|> Wizard +OldTobyTobacco --|> Tobacco +RivendellTobacco --|> Tobacco +AdvancedWizard ..|> Wizard +SecondBreakfastTobacco --|> Tobacco +SimpleWizard ..|> Wizard +@enduml \ No newline at end of file diff --git a/double-checked-locking/etc/double-checked-locking.urm.puml b/double-checked-locking/etc/double-checked-locking.urm.puml new file mode 100644 index 000000000..6feb98901 --- /dev/null +++ b/double-checked-locking/etc/double-checked-locking.urm.puml @@ -0,0 +1,20 @@ +@startuml +package com.iluwatar.doublechecked.locking { + class App { + + App() + + main(args : String[]) {static} + } + class Inventory { + - inventorySize : int + - items : List + - lock : Lock + + Inventory(inventorySize : int) + + addItem(item : Item) : boolean + + getItems() : List + } + class Item { + + Item() + } +} +Inventory --> "-items" Item +@enduml \ No newline at end of file diff --git a/double-dispatch/etc/double-dispatch.urm.puml b/double-dispatch/etc/double-dispatch.urm.puml new file mode 100644 index 000000000..725f009c0 --- /dev/null +++ b/double-dispatch/etc/double-dispatch.urm.puml @@ -0,0 +1,65 @@ +@startuml +package com.iluwatar.doubledispatch { + class App { + + App() + + main(args : String[]) {static} + } + class FlamingAsteroid { + + FlamingAsteroid(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + } + class SpaceStationIss { + + SpaceStationIss(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + } + abstract class GameObject { + - damaged : boolean + - onFire : boolean + + GameObject(left : int, top : int, right : int, bottom : int) + + collision(GameObject) {abstract} + + collisionResolve(FlamingAsteroid) {abstract} + + collisionResolve(Meteoroid) {abstract} + + collisionResolve(SpaceStationIss) {abstract} + + collisionResolve(SpaceStationMir) {abstract} + + isDamaged() : boolean + + isOnFire() : boolean + + setDamaged(damaged : boolean) + + setOnFire(onFire : boolean) + + toString() : String + } + class SpaceStationMir { + + SpaceStationMir(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + + collisionResolve(asteroid : FlamingAsteroid) + + collisionResolve(iss : SpaceStationIss) + + collisionResolve(meteoroid : Meteoroid) + + collisionResolve(mir : SpaceStationMir) + } + class Meteoroid { + + Meteoroid(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + + collisionResolve(asteroid : FlamingAsteroid) + + collisionResolve(iss : SpaceStationIss) + + collisionResolve(meteoroid : Meteoroid) + + collisionResolve(mir : SpaceStationMir) + } + class Rectangle { + - bottom : int + - left : int + - right : int + - top : int + + Rectangle(left : int, top : int, right : int, bottom : int) + + getBottom() : int + + getLeft() : int + + getRight() : int + + getTop() : int + ~ intersectsWith(r : Rectangle) : boolean + + toString() : String + } +} +FlamingAsteroid --|> Meteoroid +SpaceStationIss --|> SpaceStationMir +GameObject --|> Rectangle +SpaceStationMir --|> GameObject +Meteoroid --|> GameObject +@enduml \ No newline at end of file diff --git a/event-aggregator/etc/event-aggregator.urm.puml b/event-aggregator/etc/event-aggregator.urm.puml new file mode 100644 index 000000000..18b7621c9 --- /dev/null +++ b/event-aggregator/etc/event-aggregator.urm.puml @@ -0,0 +1,73 @@ +@startuml +package com.iluwatar.event.aggregator { + class KingsHand { + + KingsHand() + + KingsHand(obs : EventObserver) + + onEvent(e : Event) + + timePasses(day : Weekday) + } + class KingJoffrey { + + KingJoffrey() + + onEvent(e : Event) + } + class Scout { + + Scout() + + Scout(obs : EventObserver) + + timePasses(day : Weekday) + } + class LordVarys { + + LordVarys() + + LordVarys(obs : EventObserver) + + timePasses(day : Weekday) + } + class App { + + App() + + main(args : String[]) {static} + } + class LordBaelish { + + LordBaelish() + + LordBaelish(obs : EventObserver) + + timePasses(day : Weekday) + } + abstract class EventEmitter { + - observers : List + + EventEmitter() + + EventEmitter(obs : EventObserver) + # notifyObservers(e : Event) + + registerObserver(obs : EventObserver) + + timePasses(Weekday) {abstract} + } + interface EventObserver { + + onEvent(Event) {abstract} + } + enum Weekday { + + FRIDAY {static} + + MONDAY {static} + + SATURDAY {static} + + SUNDAY {static} + + THURSDAY {static} + + TUESDAY {static} + + WEDNESDAY {static} + - description : String + + toString() : String + + valueOf(name : String) : Weekday {static} + + values() : Weekday[] {static} + } + enum Event { + + STARK_SIGHTED {static} + + TRAITOR_DETECTED {static} + + WARSHIPS_APPROACHING {static} + - description : String + + toString() : String + + valueOf(name : String) : Event {static} + + values() : Event[] {static} + } +} +EventEmitter --> "-observers" EventObserver +KingsHand ..|> EventObserver +KingsHand --|> EventEmitter +KingJoffrey ..|> EventObserver +Scout --|> EventEmitter +LordVarys --|> EventEmitter +LordBaelish --|> EventEmitter +@enduml \ No newline at end of file diff --git a/event-driven-architecture/etc/event-driven-architecture.urm.puml b/event-driven-architecture/etc/event-driven-architecture.urm.puml new file mode 100644 index 000000000..55039190f --- /dev/null +++ b/event-driven-architecture/etc/event-driven-architecture.urm.puml @@ -0,0 +1,62 @@ +@startuml +package com.iluwatar.eda.handler { + class UserUpdatedEventHandler { + + UserUpdatedEventHandler() + + onEvent(event : UserUpdatedEvent) + } + class UserCreatedEventHandler { + + UserCreatedEventHandler() + + onEvent(event : UserCreatedEvent) + } +} +package com.iluwatar.eda.event { + abstract class AbstractEvent { + + AbstractEvent() + + getType() : Class + } + class UserUpdatedEvent { + - user : User + + UserUpdatedEvent(user : User) + + getUser() : User + } + class UserCreatedEvent { + - user : User + + UserCreatedEvent(user : User) + + getUser() : User + } +} +package com.iluwatar.eda.framework { + class EventDispatcher { + - handlers : Map, Handler> + + EventDispatcher() + + dispatch(event : E extends Event) + + registerHandler(eventType : Class, handler : Handler) + } + interface Event { + + getType() : Class {abstract} + } + interface Handler { + + onEvent(E extends Event) {abstract} + } +} +package com.iluwatar.eda.model { + class User { + - username : String + + User(username : String) + + getUsername() : String + } +} +package com.iluwatar.eda { + class App { + + App() + + main(args : String[]) {static} + } +} +UserCreatedEvent --> "-user" User +UserUpdatedEvent --> "-user" User +AbstractEvent ..|> Event +UserUpdatedEventHandler ..|> Handler +UserCreatedEventHandler ..|> Handler +UserUpdatedEvent --|> AbstractEvent +UserCreatedEvent --|> AbstractEvent +@enduml \ No newline at end of file diff --git a/execute-around/etc/execute-around.urm.puml b/execute-around/etc/execute-around.urm.puml new file mode 100644 index 000000000..66d23ce7a --- /dev/null +++ b/execute-around/etc/execute-around.urm.puml @@ -0,0 +1,14 @@ +@startuml +package com.iluwatar.execute.around { + interface FileWriterAction { + + writeFile(FileWriter) {abstract} + } + class SimpleFileWriter { + + SimpleFileWriter(filename : String, action : FileWriterAction) + } + class App { + + App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/facade/etc/facade.urm.puml b/facade/etc/facade.urm.puml new file mode 100644 index 000000000..f72bc2b62 --- /dev/null +++ b/facade/etc/facade.urm.puml @@ -0,0 +1,57 @@ +@startuml +package com.iluwatar.facade { + class DwarvenTunnelDigger { + + DwarvenTunnelDigger() + + name() : String + + work() + } + class DwarvenGoldmineFacade { + - workers : List + + DwarvenGoldmineFacade() + + digOutGold() + + endDay() + - makeActions(workers : Collection, actions : Action[]) {static} + + startNewDay() + } + class DwarvenGoldDigger { + + DwarvenGoldDigger() + + name() : String + + work() + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class DwarvenMineWorker { + + DwarvenMineWorker() + - action(action : Action) + + action(actions : Action[]) + + goHome() + + goToMine() + + goToSleep() + + name() : String {abstract} + + wakeUp() + + work() {abstract} + } + class DwarvenCartOperator { + + DwarvenCartOperator() + + name() : String + + work() + } + ~enum Action { + + GO_HOME {static} + + GO_TO_MINE {static} + + GO_TO_SLEEP {static} + + WAKE_UP {static} + + WORK {static} + + valueOf(name : String) : Action {static} + + values() : Action[] {static} + } +} +DwarvenGoldmineFacade --+ DwarvenMineWorker +DwarvenGoldmineFacade --> "-workers" DwarvenMineWorker +Action ..+ DwarvenMineWorker +DwarvenTunnelDigger --|> DwarvenMineWorker +DwarvenGoldDigger --|> DwarvenMineWorker +DwarvenCartOperator --|> DwarvenMineWorker +@enduml \ No newline at end of file diff --git a/factory-kit/etc/factory-kit.urm.puml b/factory-kit/etc/factory-kit.urm.puml new file mode 100644 index 000000000..faf5727eb --- /dev/null +++ b/factory-kit/etc/factory-kit.urm.puml @@ -0,0 +1,45 @@ +@startuml +package com.iluwatar.factorykit { + interface Builder { + + add(WeaponType, Supplier) {abstract} + } + class Spear { + + Spear() + + toString() : String + } + class Bow { + + Bow() + + toString() : String + } + class Sword { + + Sword() + + toString() : String + } + interface Weapon { + } + class App { + + App() + + main(args : String[]) {static} + } + class Axe { + + Axe() + + toString() : String + } + interface WeaponFactory { + + create(WeaponType) : Weapon {abstract} + + factory(consumer : Consumer) : WeaponFactory {static} + } + enum WeaponType { + + AXE {static} + + BOW {static} + + SPEAR {static} + + SWORD {static} + + valueOf(name : String) : WeaponType {static} + + values() : WeaponType[] {static} + } +} +Spear ..|> Weapon +Bow ..|> Weapon +Sword ..|> Weapon +Axe ..|> Weapon +@enduml \ No newline at end of file diff --git a/factory-method/etc/factory-method.urm.puml b/factory-method/etc/factory-method.urm.puml new file mode 100644 index 000000000..ebc9d2ff7 --- /dev/null +++ b/factory-method/etc/factory-method.urm.puml @@ -0,0 +1,53 @@ +@startuml +package com.iluwatar.factory.method { + class OrcBlacksmith { + + OrcBlacksmith() + + manufactureWeapon(weaponType : WeaponType) : Weapon + } + class ElfBlacksmith { + + ElfBlacksmith() + + manufactureWeapon(weaponType : WeaponType) : Weapon + } + class OrcWeapon { + - weaponType : WeaponType + + OrcWeapon(weaponType : WeaponType) + + getWeaponType() : WeaponType + + toString() : String + } + interface Blacksmith { + + manufactureWeapon(WeaponType) : Weapon {abstract} + } + interface Weapon { + + getWeaponType() : WeaponType {abstract} + } + class ElfWeapon { + - weaponType : WeaponType + + ElfWeapon(weaponType : WeaponType) + + getWeaponType() : WeaponType + + toString() : String + } + class App { + - blacksmith : Blacksmith + + App(blacksmith : Blacksmith) + + main(args : String[]) {static} + - manufactureWeapons() + } + enum WeaponType { + + AXE {static} + + SHORT_SWORD {static} + + SPEAR {static} + + UNDEFINED {static} + - title : String + + toString() : String + + valueOf(name : String) : WeaponType {static} + + values() : WeaponType[] {static} + } +} +ElfWeapon --> "-weaponType" WeaponType +OrcWeapon --> "-weaponType" WeaponType +App --> "-blacksmith" Blacksmith +OrcBlacksmith ..|> Blacksmith +ElfBlacksmith ..|> Blacksmith +OrcWeapon ..|> Weapon +ElfWeapon ..|> Weapon +@enduml \ No newline at end of file diff --git a/feature-toggle/etc/feature-toggle.urm.puml b/feature-toggle/etc/feature-toggle.urm.puml new file mode 100644 index 000000000..762d49cb3 --- /dev/null +++ b/feature-toggle/etc/feature-toggle.urm.puml @@ -0,0 +1,47 @@ +@startuml +package com.iluwatar.featuretoggle.pattern { + interface Service { + + getWelcomeMessage(User) : String {abstract} + + isEnhanced() : boolean {abstract} + } +} +package com.iluwatar.featuretoggle.user { + class User { + - name : String + + User(name : String) + + toString() : String + } + class UserGroup { + - freeGroup : List {static} + - paidGroup : List {static} + + UserGroup() + + addUserToFreeGroup(user : User) {static} + + addUserToPaidGroup(user : User) {static} + + isPaid(user : User) : boolean {static} + } +} +package com.iluwatar.featuretoggle.pattern.propertiesversion { + class PropertiesFeatureToggleVersion { + - isEnhanced : boolean + + PropertiesFeatureToggleVersion(properties : Properties) + + getWelcomeMessage(user : User) : String + + isEnhanced() : boolean + } +} +package com.iluwatar.featuretoggle.pattern.tieredversion { + class TieredFeatureToggleVersion { + + TieredFeatureToggleVersion() + + getWelcomeMessage(user : User) : String + + isEnhanced() : boolean + } +} +package com.iluwatar.featuretoggle { + class App { + + App() + + main(args : String[]) {static} + } +} +UserGroup --> "-freeGroup" User +TieredFeatureToggleVersion ..|> Service +PropertiesFeatureToggleVersion ..|> Service +@enduml \ No newline at end of file diff --git a/fluentinterface/etc/fluentinterface.urm.puml b/fluentinterface/etc/fluentinterface.urm.puml new file mode 100644 index 000000000..436fcb2e8 --- /dev/null +++ b/fluentinterface/etc/fluentinterface.urm.puml @@ -0,0 +1,71 @@ +@startuml +package com.iluwatar.fluentinterface.fluentiterable.simple { + class SimpleFluentIterable { + - iterable : Iterable + # SimpleFluentIterable(iterable : Iterable) + + asList() : List + + filter(predicate : Predicate) : FluentIterable + + first() : Optional + + first(count : int) : FluentIterable + + forEach(action : Consumer) + + from(iterable : Iterable) : FluentIterable {static} + + fromCopyOf(iterable : Iterable) : FluentIterable {static} + + getRemainingElementsCount() : int + + iterator() : Iterator + + last() : Optional + + last(count : int) : FluentIterable + + map(function : Function) : FluentIterable + + spliterator() : Spliterator + + toList(iterator : Iterator) : List {static} + } +} +package com.iluwatar.fluentinterface.app { + class App { + + App() + + main(args : String[]) {static} + - negatives() : Predicate {static} + - positives() : Predicate {static} + - prettyPrint(delimiter : String, prefix : String, iterable : Iterable) {static} + - prettyPrint(prefix : String, iterable : Iterable) {static} + - transformToString() : Function {static} + } +} +package com.iluwatar.fluentinterface.fluentiterable.lazy { + class LazyFluentIterable { + - iterable : Iterable + # LazyFluentIterable() + # LazyFluentIterable(iterable : Iterable) + + asList() : List + + filter(predicate : Predicate) : FluentIterable + + first() : Optional + + first(count : int) : FluentIterable + + from(iterable : Iterable) : FluentIterable {static} + + iterator() : Iterator + + last() : Optional + + last(count : int) : FluentIterable + + map(function : Function) : FluentIterable + } + abstract class DecoratingIterator { + # fromIterator : Iterator + - next : E + + DecoratingIterator(fromIterator : Iterator) + + computeNext() : E {abstract} + + hasNext() : boolean + + next() : E + } +} +package com.iluwatar.fluentinterface.fluentiterable { + interface FluentIterable { + + asList() : List {abstract} + + copyToList(iterable : Iterable) : List {static} + + filter(Predicate) : FluentIterable {abstract} + + first() : Optional {abstract} + + first(int) : FluentIterable {abstract} + + last() : Optional {abstract} + + last(int) : FluentIterable {abstract} + + map(Function) : FluentIterable {abstract} + } +} +LazyFluentIterable ..|> FluentIterable +SimpleFluentIterable ..|> FluentIterable +@enduml \ No newline at end of file diff --git a/flux/etc/flux.urm.puml b/flux/etc/flux.urm.puml new file mode 100644 index 000000000..e4bece2fc --- /dev/null +++ b/flux/etc/flux.urm.puml @@ -0,0 +1,115 @@ +@startuml +package com.iluwatar.flux.view { + class ContentView { + - content : Content + + ContentView() + + render() + + storeChanged(store : Store) + } + class MenuView { + - selected : MenuItem + + MenuView() + + itemClicked(item : MenuItem) + + render() + + storeChanged(store : Store) + } + interface View { + + render() {abstract} + + storeChanged(Store) {abstract} + } +} +package com.iluwatar.flux.action { + class ContentAction { + - content : Content + + ContentAction(content : Content) + + getContent() : Content + } + class MenuAction { + - menuItem : MenuItem + + MenuAction(menuItem : MenuItem) + + getMenuItem() : MenuItem + } + abstract class Action { + - type : ActionType + + Action(type : ActionType) + + getType() : ActionType + } + enum MenuItem { + + COMPANY {static} + + HOME {static} + + PRODUCTS {static} + - title : String + + toString() : String + + valueOf(name : String) : MenuItem {static} + + values() : MenuItem[] {static} + } + enum Content { + + COMPANY {static} + + PRODUCTS {static} + - title : String + + toString() : String + + valueOf(name : String) : Content {static} + + values() : Content[] {static} + } + enum ActionType { + + CONTENT_CHANGED {static} + + MENU_ITEM_SELECTED {static} + + valueOf(name : String) : ActionType {static} + + values() : ActionType[] {static} + } +} +package com.iluwatar.flux.app { + class App { + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.flux.store { + abstract class Store { + - views : List + + Store() + # notifyChange() + + onAction(Action) {abstract} + + registerView(view : View) + } + class ContentStore { + - content : Content + + ContentStore() + + getContent() : Content + + onAction(action : Action) + } + class MenuStore { + - selected : MenuItem + + MenuStore() + + getSelected() : MenuItem + + onAction(action : Action) + } +} +package com.iluwatar.flux.dispatcher { + class Dispatcher { + - instance : Dispatcher {static} + - stores : List + - Dispatcher() + - dispatchAction(action : Action) + + getInstance() : Dispatcher {static} + + menuItemSelected(menuItem : MenuItem) + + registerStore(store : Store) + } +} +MenuAction --> "-menuItem" MenuItem +Action --> "-type" ActionType +MenuStore --> "-selected" MenuItem +Dispatcher --> "-instance" Dispatcher +ContentView --> "-content" Content +Dispatcher --> "-stores" Store +MenuView --> "-selected" MenuItem +Store --> "-views" View +ContentStore --> "-content" Content +ContentAction --> "-content" Content +ContentAction --|> Action +ContentStore --|> Store +ContentView ..|> View +MenuAction --|> Action +MenuView ..|> View +MenuStore --|> Store +@enduml \ No newline at end of file diff --git a/flyweight/etc/flyweight.urm.puml b/flyweight/etc/flyweight.urm.puml new file mode 100644 index 000000000..98a2b4721 --- /dev/null +++ b/flyweight/etc/flyweight.urm.puml @@ -0,0 +1,60 @@ +@startuml +package com.iluwatar.flyweight { + class PoisonPotion { + + PoisonPotion() + + drink() + } + class StrengthPotion { + + StrengthPotion() + + drink() + } + class HealingPotion { + + HealingPotion() + + drink() + } + class PotionFactory { + - potions : Map + + PotionFactory() + ~ createPotion(type : PotionType) : Potion + } + interface Potion { + + drink() {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class AlchemistShop { + - bottomShelf : List + - topShelf : List + + AlchemistShop() + + enumerate() + - fillShelves() + + getBottomShelf() : List + + getTopShelf() : List + } + class HolyWaterPotion { + + HolyWaterPotion() + + drink() + } + class InvisibilityPotion { + + InvisibilityPotion() + + drink() + } + enum PotionType { + + HEALING {static} + + HOLY_WATER {static} + + INVISIBILITY {static} + + POISON {static} + + STRENGTH {static} + + valueOf(name : String) : PotionType {static} + + values() : PotionType[] {static} + } +} +AlchemistShop --> "-topShelf" Potion +PoisonPotion ..|> Potion +StrengthPotion ..|> Potion +HealingPotion ..|> Potion +HolyWaterPotion ..|> Potion +InvisibilityPotion ..|> Potion +@enduml \ No newline at end of file diff --git a/front-controller/etc/front-controller.urm.puml b/front-controller/etc/front-controller.urm.puml new file mode 100644 index 000000000..17ccebae1 --- /dev/null +++ b/front-controller/etc/front-controller.urm.puml @@ -0,0 +1,50 @@ +@startuml +package com.iluwatar.front.controller { + class App { + + App() + + main(args : String[]) {static} + } + class FrontController { + + FrontController() + - getCommand(request : String) : Command + - getCommandClass(request : String) : Class {static} + + handleRequest(request : String) + } + class ArcherView { + + ArcherView() + + display() + } + interface View { + + display() {abstract} + } + interface Command { + + process() {abstract} + } + class ErrorView { + + ErrorView() + + display() + } + class ArcherCommand { + + ArcherCommand() + + process() + } + class CatapultView { + + CatapultView() + + display() + } + class CatapultCommand { + + CatapultCommand() + + process() + } + class UnknownCommand { + + UnknownCommand() + + process() + } +} +ArcherView ..|> View +ErrorView ..|> View +ArcherCommand ..|> Command +CatapultView ..|> View +CatapultCommand ..|> Command +UnknownCommand ..|> Command +@enduml \ No newline at end of file diff --git a/half-sync-half-async/etc/half-sync-half-async.urm.puml b/half-sync-half-async/etc/half-sync-half-async.urm.puml new file mode 100644 index 000000000..e733dd586 --- /dev/null +++ b/half-sync-half-async/etc/half-sync-half-async.urm.puml @@ -0,0 +1,30 @@ +@startuml +package com.iluwatar.halfsynchalfasync { + class App { + + App() + - ap(i : long) : long {static} + + main(args : String[]) {static} + } + interface AsyncTask { + + call() : O {abstract} + + onError(Throwable) {abstract} + + onPostCall(O) {abstract} + + onPreCall() {abstract} + } + ~class ArithmeticSumTask { + - n : long + + ArithmeticSumTask(n : long) + + call() : Long + + onError(throwable : Throwable) + + onPostCall(result : Long) + + onPreCall() + } + class AsynchronousService { + - service : ExecutorService + + AsynchronousService(workQueue : BlockingQueue) + + execute(task : AsyncTask) + } +} +ArithmeticSumTask ..+ App +ArithmeticSumTask ..|> AsyncTask +@enduml \ No newline at end of file diff --git a/hexagonal/etc/hexagonal.urm.puml b/hexagonal/etc/hexagonal.urm.puml new file mode 100644 index 000000000..4102c5863 --- /dev/null +++ b/hexagonal/etc/hexagonal.urm.puml @@ -0,0 +1,183 @@ +@startuml +package com.iluwatar.hexagonal.service { + class LotteryServiceImpl { + - bank : WireTransfers + - notifications : LotteryNotifications + - repository : LotteryTicketRepository + + LotteryServiceImpl() + + checkTicketForPrize(id : LotteryTicketId, winningNumbers : LotteryNumbers) : LotteryTicketCheckResult + + submitTicket(ticket : LotteryTicket) : Optional + } + interface LotteryService { + + checkTicketForPrize(LotteryTicketId, LotteryNumbers) : LotteryTicketCheckResult {abstract} + + submitTicket(LotteryTicket) : Optional {abstract} + } +} +package com.iluwatar.hexagonal.domain { + class LotteryTicketId { + - id : UUID + + LotteryTicketId() + + getId() : UUID + } + class LotteryConstants { + + PLAYER_MAX_SALDO : int {static} + + PRIZE_AMOUNT : int {static} + + SERVICE_BANK_ACCOUNT : String {static} + + SERVICE_BANK_ACCOUNT_SALDO : 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) + + create(givenNumbers : Set) : LotteryNumbers {static} + + createRandom() : LotteryNumbers {static} + + equals(obj : Object) : boolean + - generateRandomNumbers() + + getNumbers() : Set + + hashCode() : int + } + class PlayerDetails { + - bankAccountNumber : String + - emailAddress : String + - phoneNumber : String + - PlayerDetails(email : String, bankAccount : String, phone : String) + + create(email : String, bankAccount : String, phone : String) : PlayerDetails {static} + + equals(obj : Object) : boolean + + getBankAccount() : String + + getEmail() : String + + getPhoneNumber() : String + + hashCode() : int + } + class LotteryTicketCheckResult { + - checkResult : CheckResult + - prizeAmount : int + + LotteryTicketCheckResult(result : CheckResult) + + LotteryTicketCheckResult(result : CheckResult, amount : int) + + equals(obj : Object) : boolean + + getPrizeAmount() : int + + getResult() : CheckResult + + hashCode() : int + } + class LotteryTicket { + - lotteryNumbers : LotteryNumbers + - playerDetails : PlayerDetails + - LotteryTicket(details : PlayerDetails, numbers : LotteryNumbers) + + create(details : PlayerDetails, numbers : LotteryNumbers) : LotteryTicket {static} + + equals(obj : Object) : boolean + + getNumbers() : LotteryNumbers + + getPlayerDetails() : PlayerDetails + + hashCode() : int + } + -class RandomNumberGenerator { + - randomIterator : OfInt + + RandomNumberGenerator(min : int, max : int) + + nextInt() : int + } + enum CheckResult { + + NO_PRIZE {static} + + TICKET_NOT_SUBMITTED {static} + + WIN_PRIZE {static} + + valueOf(name : String) : CheckResult {static} + + values() : CheckResult[] {static} + } +} +package com.iluwatar.hexagonal.banking { + class WireTransfersImpl { + - accounts : Map {static} + + WireTransfersImpl() + + getFunds(bankAccount : String) : int + + setFunds(bankAccount : String, amount : int) + + transferFunds(amount : int, sourceBackAccount : String, destinationBankAccount : String) : boolean + } + interface WireTransfers { + + getFunds(String) : int {abstract} + + setFunds(String, int) {abstract} + + transferFunds(int, String, String) : boolean {abstract} + } +} +package com.iluwatar.hexagonal.database { + class LotteryTicketInMemoryRepository { + - tickets : Map {static} + + LotteryTicketInMemoryRepository() + + 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} + } +} +package com.iluwatar.hexagonal.notifications { + interface LotteryNotifications { + + notifyNoWin(PlayerDetails) {abstract} + + notifyPrize(PlayerDetails, int) {abstract} + + notifyPrizeError(PlayerDetails, int) {abstract} + + notifyTicketSubmitError(PlayerDetails) {abstract} + + notifyTicketSubmitted(PlayerDetails) {abstract} + } + class LotteryNotificationsImpl { + + LotteryNotificationsImpl() + + notifyNoWin(details : PlayerDetails) + + notifyPrize(details : PlayerDetails, prizeAmount : int) + + notifyPrizeError(details : PlayerDetails, prizeAmount : int) + + notifyTicketSubmitError(details : PlayerDetails) + + notifyTicketSubmitted(details : PlayerDetails) + } +} +package com.iluwatar.hexagonal { + class App { + - allPlayerDetails : List {static} + + App() + - getRandomPlayerDetails() : PlayerDetails {static} + + main(args : String[]) {static} + - submitTickets(lotteryService : LotteryService, numTickets : int) {static} + } +} +package com.iluwatar.hexagonal.administration { + interface LotteryAdministration { + + getAllSubmittedTickets() : Map {abstract} + + performLottery() : LotteryNumbers {abstract} + + resetLottery() {abstract} + } + class LotteryAdministrationImpl { + - bank : WireTransfers + - notifications : LotteryNotifications + - repository : LotteryTicketRepository + - service : LotteryService + + LotteryAdministrationImpl() + + getAllSubmittedTickets() : Map + + performLottery() : LotteryNumbers + + resetLottery() + } +} +LotteryTicket --> "-playerDetails" PlayerDetails +LotteryAdministrationImpl --> "-bank" WireTransfers +App --> "-allPlayerDetails" PlayerDetails +RandomNumberGenerator ..+ PrimitiveIterator +LotteryAdministrationImpl --> "-repository" LotteryTicketRepository +LotteryAdministrationImpl --+ LotteryTicketCheckResult +LotteryServiceImpl --> "-notifications" LotteryNotifications +LotteryTicket --> "-lotteryNumbers" LotteryNumbers +LotteryAdministrationImpl --> "-notifications" LotteryNotifications +LotteryServiceImpl --> "-repository" LotteryTicketRepository +LotteryServiceImpl --+ LotteryTicketCheckResult +LotteryServiceImpl --> "-bank" WireTransfers +RandomNumberGenerator ..+ LotteryNumbers +LotteryAdministrationImpl --> "-service" LotteryService +LotteryTicketCheckResult --> "-checkResult" CheckResult +CheckResult ..+ LotteryTicketCheckResult +LotteryTicketInMemoryRepository ..|> LotteryTicketRepository +WireTransfersImpl ..|> WireTransfers +LotteryServiceImpl ..|> LotteryService +LotteryNotificationsImpl ..|> LotteryNotifications +LotteryAdministrationImpl ..|> LotteryAdministration +@enduml \ No newline at end of file diff --git a/intercepting-filter/etc/intercepting-filter.urm.puml b/intercepting-filter/etc/intercepting-filter.urm.puml new file mode 100644 index 000000000..f5bfb54e4 --- /dev/null +++ b/intercepting-filter/etc/intercepting-filter.urm.puml @@ -0,0 +1,88 @@ +@startuml +package com.iluwatar.intercepting.filter { + interface Filter { + + execute(Order) : String {abstract} + + getLast() : Filter {abstract} + + getNext() : Filter {abstract} + + setNext(Filter) {abstract} + } + abstract class AbstractFilter { + - next : Filter + + AbstractFilter() + + AbstractFilter(next : Filter) + + execute(order : Order) : String + + getLast() : Filter + + getNext() : Filter + + setNext(filter : Filter) + } + class ContactFilter { + + ContactFilter() + + execute(order : Order) : String + } + class OrderFilter { + + OrderFilter() + + execute(order : Order) : String + } + class Order { + - address : String + - contactNumber : String + - depositNumber : String + - name : String + - order : String + + Order() + + Order(name : String, contactNumber : String, address : String, depositNumber : String, order : String) + + getAddress() : String + + getContactNumber() : String + + getDepositNumber() : String + + getName() : String + + getOrder() : String + + setAddress(address : String) + + setContactNumber(contactNumber : String) + + setDepositNumber(depositNumber : String) + + setName(name : String) + + setOrder(order : String) + } + class AddressFilter { + + AddressFilter() + + execute(order : Order) : String + } + ~class DListener { + ~ DListener(this$0 : Target) + + actionPerformed(e : ActionEvent) + } + class FilterManager { + - filterChain : FilterChain + + FilterManager() + + addFilter(filter : Filter) + + filterRequest(order : Order) : String + } + class FilterChain { + - chain : Filter + + FilterChain() + + addFilter(filter : Filter) + + execute(order : Order) : String + } + class DepositFilter { + + DepositFilter() + + execute(order : Order) : String + } + class App { + + App() + + main(args : String[]) {static} + } + class NameFilter { + + NameFilter() + + execute(order : Order) : String + } +} +AbstractFilter --> "-next" Filter +DListener --+ Target +FilterChain --> "-chain" Filter +FilterManager --> "-filterChain" FilterChain +AbstractFilter ..|> Filter +ContactFilter --|> AbstractFilter +OrderFilter --|> AbstractFilter +AddressFilter --|> AbstractFilter +DepositFilter --|> AbstractFilter +NameFilter --|> AbstractFilter +@enduml \ No newline at end of file diff --git a/interpreter/etc/interpreter.urm.puml b/interpreter/etc/interpreter.urm.puml new file mode 100644 index 000000000..bdbd369d6 --- /dev/null +++ b/interpreter/etc/interpreter.urm.puml @@ -0,0 +1,50 @@ +@startuml +package com.iluwatar.interpreter { + abstract class Expression { + + Expression() + + interpret() : int {abstract} + + toString() : String {abstract} + } + class PlusExpression { + - leftExpression : Expression + - rightExpression : Expression + + PlusExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } + class App { + + App() + + getOperatorInstance(s : String, left : Expression, right : Expression) : Expression {static} + + isOperator(s : String) : boolean {static} + + main(args : String[]) {static} + } + class NumberExpression { + - number : int + + NumberExpression(number : int) + + NumberExpression(s : String) + + interpret() : int + + toString() : String + } + class MultiplyExpression { + - leftExpression : Expression + - rightExpression : Expression + + MultiplyExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } + class MinusExpression { + - leftExpression : Expression + - rightExpression : Expression + + MinusExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } +} +MultiplyExpression --> "-leftExpression" Expression +MinusExpression --> "-leftExpression" Expression +PlusExpression --> "-leftExpression" Expression +PlusExpression --|> Expression +NumberExpression --|> Expression +MultiplyExpression --|> Expression +MinusExpression --|> Expression +@enduml \ No newline at end of file diff --git a/iterator/etc/iterator.urm.puml b/iterator/etc/iterator.urm.puml new file mode 100644 index 000000000..cbafd6595 --- /dev/null +++ b/iterator/etc/iterator.urm.puml @@ -0,0 +1,48 @@ +@startuml +package com.iluwatar.iterator { + interface ItemIterator { + + hasNext() : boolean {abstract} + + next() : Item {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class TreasureChestItemIterator { + - chest : TreasureChest + - idx : int + - type : ItemType + + TreasureChestItemIterator(chest : TreasureChest, type : ItemType) + - findNextIdx() : int + + hasNext() : boolean + + next() : Item + } + class TreasureChest { + - items : List + + TreasureChest() + + getItems() : List + ~ iterator(itemType : ItemType) : ItemIterator + } + class Item { + - name : String + - type : ItemType + + Item(type : ItemType, name : String) + + getType() : ItemType + + setType(type : ItemType) + + toString() : String + } + enum ItemType { + + ANY {static} + + POTION {static} + + RING {static} + + WEAPON {static} + + valueOf(name : String) : ItemType {static} + + values() : ItemType[] {static} + } +} +Item --> "-type" ItemType +TreasureChest --> "-items" Item +TreasureChestItemIterator --> "-type" ItemType +TreasureChestItemIterator --> "-chest" TreasureChest +TreasureChestItemIterator ..|> ItemIterator +@enduml \ No newline at end of file diff --git a/layers/etc/layers.urm.puml b/layers/etc/layers.urm.puml new file mode 100644 index 000000000..d67216ff8 --- /dev/null +++ b/layers/etc/layers.urm.puml @@ -0,0 +1,125 @@ +@startuml +package com.iluwatar.layers { + interface View { + + render() {abstract} + } + class CakeBakingServiceImpl { + - context : AbstractApplicationContext + + CakeBakingServiceImpl() + + bakeNewCake(cakeInfo : CakeInfo) + + getAllCakes() : List + - getAvailableLayerEntities() : List + + getAvailableLayers() : List + - getAvailableToppingEntities() : List + + getAvailableToppings() : List + + saveNewLayer(layerInfo : CakeLayerInfo) + + saveNewTopping(toppingInfo : CakeToppingInfo) + } + interface CakeDao { + } + class CakeTopping { + - cake : Cake + - calories : int + - id : Long + - name : String + + CakeTopping() + + CakeTopping(name : String, calories : int) + + getCake() : Cake + + getCalories() : int + + getId() : Long + + getName() : String + + setCake(cake : Cake) + + setCalories(calories : int) + + setId(id : Long) + + setName(name : String) + + toString() : String + } + class CakeLayerInfo { + + calories : int + + id : Optional + + name : String + + CakeLayerInfo(id : Long, name : String, calories : int) + + CakeLayerInfo(name : String, calories : int) + + toString() : String + } + interface CakeLayerDao { + } + interface CakeToppingDao { + } + interface CakeBakingService { + + bakeNewCake(CakeInfo) {abstract} + + getAllCakes() : List {abstract} + + getAvailableLayers() : List {abstract} + + getAvailableToppings() : List {abstract} + + saveNewLayer(CakeLayerInfo) {abstract} + + saveNewTopping(CakeToppingInfo) {abstract} + } + class CakeViewImpl { + - cakeBakingService : CakeBakingService + + CakeViewImpl(cakeBakingService : CakeBakingService) + + render() + } + class CakeToppingInfo { + + calories : int + + id : Optional + + name : String + + CakeToppingInfo(id : Long, name : String, calories : int) + + CakeToppingInfo(name : String, calories : int) + + toString() : String + } + class CakeInfo { + + cakeLayerInfos : List + + cakeToppingInfo : CakeToppingInfo + + id : Optional + + CakeInfo(cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) + + CakeInfo(id : Long, cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) + + calculateTotalCalories() : int + + toString() : String + } + class App { + - cakeBakingService : CakeBakingService {static} + + App() + - initializeData(cakeBakingService : CakeBakingService) {static} + + main(args : String[]) {static} + } + class Cake { + - id : Long + - layers : Set + - topping : CakeTopping + + Cake() + + addLayer(layer : CakeLayer) + + getId() : Long + + getLayers() : Set + + getTopping() : CakeTopping + + setId(id : Long) + + setLayers(layers : Set) + + setTopping(topping : CakeTopping) + + toString() : String + } + class CakeLayer { + - cake : Cake + - calories : int + - id : Long + - name : String + + CakeLayer() + + CakeLayer(name : String, calories : int) + + getCake() : Cake + + getCalories() : int + + getId() : Long + + getName() : String + + setCake(cake : Cake) + + setCalories(calories : int) + + setId(id : Long) + + setName(name : String) + + toString() : String + } +} +CakeViewImpl --> "-cakeBakingService" CakeBakingService +CakeInfo --> "-cakeToppingInfo" CakeToppingInfo +CakeInfo --> "-cakeLayerInfos" CakeLayerInfo +App --> "-cakeBakingService" CakeBakingService +CakeLayer --> "-cake" Cake +Cake --> "-topping" CakeTopping +CakeBakingServiceImpl ..|> CakeBakingService +CakeViewImpl ..|> View +@enduml \ No newline at end of file diff --git a/lazy-loading/etc/lazy-loading.urm.puml b/lazy-loading/etc/lazy-loading.urm.puml new file mode 100644 index 000000000..96c427553 --- /dev/null +++ b/lazy-loading/etc/lazy-loading.urm.puml @@ -0,0 +1,35 @@ +@startuml +package com.iluwatar.lazy.loading { + ~class HeavyFactory { + - heavyInstance : Heavy + ~ HeavyFactory(this$0 : Java8Holder) + + get() : Heavy + } + class HolderNaive { + - heavy : Heavy + + HolderNaive() + + getHeavy() : Heavy + } + class Heavy { + + Heavy() + } + class HolderThreadSafe { + - heavy : Heavy + + HolderThreadSafe() + + getHeavy() : Heavy + } + class Java8Holder { + - heavy : Supplier + + Java8Holder() + - createAndCacheHeavy() : Heavy + + getHeavy() : Heavy + } + class App { + + App() + + main(args : String[]) {static} + } +} +HolderThreadSafe --> "-heavy" Heavy +HolderNaive --> "-heavy" Heavy +HeavyFactory --> "-heavyInstance" Heavy +@enduml \ No newline at end of file diff --git a/mediator/etc/mediator.urm.puml b/mediator/etc/mediator.urm.puml new file mode 100644 index 000000000..0b3baab5a --- /dev/null +++ b/mediator/etc/mediator.urm.puml @@ -0,0 +1,68 @@ +@startuml +package com.iluwatar.mediator { + class App { + + App() + + main(args : String[]) {static} + } + class Hobbit { + + Hobbit() + + toString() : String + } + interface PartyMember { + + act(Action) {abstract} + + joinedParty(Party) {abstract} + + partyAction(Action) {abstract} + } + interface Party { + + act(PartyMember, Action) {abstract} + + addMember(PartyMember) {abstract} + } + class Wizard { + + Wizard() + + toString() : String + } + class PartyImpl { + - members : List + + PartyImpl() + + act(actor : PartyMember, action : Action) + + addMember(member : PartyMember) + } + class Hunter { + + Hunter() + + toString() : String + } + class Rogue { + + Rogue() + + toString() : String + } + abstract class PartyMemberBase { + # party : Party + + PartyMemberBase() + + act(action : Action) + + joinedParty(party : Party) + + partyAction(action : Action) + + toString() : String {abstract} + } + enum Action { + + ENEMY {static} + + GOLD {static} + + HUNT {static} + + NONE {static} + + TALE {static} + - description : String + - title : String + + getDescription() : String + + toString() : String + + valueOf(name : String) : Action {static} + + values() : Action[] {static} + } +} +PartyImpl --> "-members" PartyMember +PartyMemberBase --> "-party" Party +Hobbit --|> PartyMemberBase +Wizard --|> PartyMemberBase +PartyImpl ..|> Party +Hunter --|> PartyMemberBase +Rogue --|> PartyMemberBase +PartyMemberBase ..|> PartyMember +@enduml \ No newline at end of file diff --git a/memento/etc/memento.urm.puml b/memento/etc/memento.urm.puml new file mode 100644 index 000000000..aa63b4ebe --- /dev/null +++ b/memento/etc/memento.urm.puml @@ -0,0 +1,48 @@ +@startuml +package com.iluwatar.memento { + class Star { + - ageYears : int + - massTons : int + - type : StarType + + Star(startType : StarType, startAge : int, startMass : int) + ~ getMemento() : StarMemento + ~ setMemento(memento : StarMemento) + + timePasses() + + toString() : String + } + interface StarMemento { + } + -class StarMementoInternal { + - ageYears : int + - massTons : int + - type : StarType + - StarMementoInternal() + + getAgeYears() : int + + getMassTons() : int + + getType() : StarType + + setAgeYears(ageYears : int) + + setMassTons(massTons : int) + + setType(type : StarType) + } + class App { + + App() + + main(args : String[]) {static} + } + enum StarType { + + DEAD {static} + + RED_GIANT {static} + + SUN {static} + + SUPERNOVA {static} + + UNDEFINED {static} + + WHITE_DWARF {static} + - title : String + + toString() : String + + valueOf(name : String) : StarType {static} + + values() : StarType[] {static} + } +} +StarMementoInternal --> "-type" StarType +Star --> "-type" StarType +StarMementoInternal ..+ Star +StarMementoInternal ..|> StarMemento +@enduml \ No newline at end of file diff --git a/message-channel/etc/message-channel.urm.puml b/message-channel/etc/message-channel.urm.puml new file mode 100644 index 000000000..9e2b24032 --- /dev/null +++ b/message-channel/etc/message-channel.urm.puml @@ -0,0 +1,8 @@ +@startuml +package com.iluwatar.message.channel { + class App { + + App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/model-view-controller/etc/model-view-controller.urm.puml b/model-view-controller/etc/model-view-controller.urm.puml new file mode 100644 index 000000000..f8137bdae --- /dev/null +++ b/model-view-controller/etc/model-view-controller.urm.puml @@ -0,0 +1,69 @@ +@startuml +package com.iluwatar.model.view.controller { + class GiantModel { + - fatigue : Fatigue + - health : Health + - nourishment : Nourishment + ~ GiantModel(health : Health, fatigue : Fatigue, nourishment : Nourishment) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + toString() : String + } + class App { + + App() + + main(args : String[]) {static} + } + class GiantView { + + GiantView() + + displayGiant(giant : GiantModel) + } + class GiantController { + - giant : GiantModel + - view : GiantView + + GiantController(giant : GiantModel, view : GiantView) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + updateView() + } + enum Nourishment { + + HUNGRY {static} + + SATURATED {static} + + STARVING {static} + - title : String + + toString() : String + + valueOf(name : String) : Nourishment {static} + + values() : Nourishment[] {static} + } + enum Fatigue { + + ALERT {static} + + SLEEPING {static} + + TIRED {static} + - title : String + + toString() : String + + valueOf(name : String) : Fatigue {static} + + values() : Fatigue[] {static} + } + enum Health { + + DEAD {static} + + HEALTHY {static} + + WOUNDED {static} + - title : String + + toString() : String + + valueOf(name : String) : Health {static} + + values() : Health[] {static} + } +} +GiantModel --> "-nourishment" Nourishment +GiantController --> "-giant" GiantModel +GiantModel --> "-fatigue" Fatigue +GiantModel --> "-health" Health +GiantController --> "-view" GiantView +@enduml \ No newline at end of file diff --git a/model-view-presenter/etc/model-view-presenter.urm.puml b/model-view-presenter/etc/model-view-presenter.urm.puml new file mode 100644 index 000000000..64bcfba32 --- /dev/null +++ b/model-view-presenter/etc/model-view-presenter.urm.puml @@ -0,0 +1,87 @@ +@startuml +package com.iluwatar.model.view.presenter { + class FileLoader { + - fileName : String + - loaded : boolean + + FileLoader() + + fileExists() : boolean + + getFileName() : String + + isLoaded() : boolean + + loadData() : String + + setFileName(fileName : String) + } + class FileSelectorJFrame { + - area : JTextArea + - cancel : JButton + - contents : JLabel + - fileName : String + - info : JLabel + - input : JTextField + - ok : JButton + - panel : JPanel + - presenter : FileSelectorPresenter + - serialVersionUID : long {static} + + FileSelectorJFrame() + + actionPerformed(e : ActionEvent) + + close() + + displayData(data : String) + + getFileName() : String + + getPresenter() : FileSelectorPresenter + + isOpened() : boolean + + open() + + setFileName(name : String) + + setPresenter(presenter : FileSelectorPresenter) + + showMessage(message : String) + } + class App { + + App() + + main(args : String[]) {static} + } + interface FileSelectorView { + + close() {abstract} + + displayData(String) {abstract} + + getFileName() : String {abstract} + + getPresenter() : FileSelectorPresenter {abstract} + + isOpened() : boolean {abstract} + + open() {abstract} + + setFileName(String) {abstract} + + setPresenter(FileSelectorPresenter) {abstract} + + showMessage(String) {abstract} + } + class FileSelectorStub { + - dataDisplayed : boolean + - name : String + - numOfMessageSent : int + - opened : boolean + - presenter : FileSelectorPresenter + + FileSelectorStub() + + close() + + dataDisplayed() : boolean + + displayData(data : String) + + getFileName() : String + + getMessagesSent() : int + + getPresenter() : FileSelectorPresenter + + isOpened() : boolean + + open() + + setFileName(name : String) + + setPresenter(presenter : FileSelectorPresenter) + + showMessage(message : String) + } + class FileSelectorPresenter { + - loader : FileLoader + - view : FileSelectorView + + FileSelectorPresenter(view : FileSelectorView) + + cancelled() + + confirmed() + + fileNameChanged() + + setLoader(loader : FileLoader) + + start() + } +} +FileSelectorStub --> "-presenter" FileSelectorPresenter +FileSelectorJFrame --> "-presenter" FileSelectorPresenter +FileSelectorPresenter --> "-loader" FileLoader +FileSelectorPresenter --> "-view" FileSelectorView +FileSelectorJFrame ..|> FileSelectorView +FileSelectorStub ..|> FileSelectorView +@enduml \ No newline at end of file diff --git a/monad/etc/monad.urm.puml b/monad/etc/monad.urm.puml new file mode 100644 index 000000000..6fe037064 --- /dev/null +++ b/monad/etc/monad.urm.puml @@ -0,0 +1,35 @@ +@startuml +package com.iluwatar.monad { + class Validator { + - exceptions : List + - t : T + - Validator(t : T) + + get() : T + + of(t : T) : Validator {static} + + validate(projection : Function, validation : Predicate, message : String) : Validator + + validate(validation : Predicate, message : String) : Validator + } + class App { + + App() + + main(args : String[]) {static} + } + class User { + - age : int + - email : String + - name : String + - sex : Sex + + User(name : String, age : int, sex : Sex, email : String) + + getAge() : int + + getEmail() : String + + getName() : String + + getSex() : Sex + } + enum Sex { + + FEMALE {static} + + MALE {static} + + valueOf(name : String) : Sex {static} + + values() : Sex[] {static} + } +} +User --> "-sex" Sex +@enduml \ No newline at end of file diff --git a/monostate/etc/monostate.urm.puml b/monostate/etc/monostate.urm.puml new file mode 100644 index 000000000..3c09bb4ed --- /dev/null +++ b/monostate/etc/monostate.urm.puml @@ -0,0 +1,32 @@ +@startuml +package com.iluwatar.monostate { + class LoadBalancer { + - id : int {static} + - lastServedId : int {static} + - servers : List {static} + + LoadBalancer() + + addServer(server : Server) + + getLastServedId() : int {static} + + getNoOfServers() : int + + serverRequest(request : Request) + } + class App { + + App() + + main(args : String[]) {static} + } + class Request { + + value : String + + Request(value : String) + } + class Server { + + host : String + + id : int + + port : int + + Server(host : String, port : int, id : int) + + getHost() : String + + getPort() : int + + serve(request : Request) + } +} +LoadBalancer --> "-servers" Server +@enduml \ No newline at end of file diff --git a/multiton/etc/multiton.urm.puml b/multiton/etc/multiton.urm.puml new file mode 100644 index 000000000..c582a6379 --- /dev/null +++ b/multiton/etc/multiton.urm.puml @@ -0,0 +1,29 @@ +@startuml +package com.iluwatar.multiton { + class App { + + App() + + main(args : String[]) {static} + } + class Nazgul { + - name : NazgulName + - nazguls : Map {static} + - Nazgul(name : NazgulName) + + getInstance(name : NazgulName) : Nazgul {static} + + getName() : NazgulName + } + enum NazgulName { + + ADUNAPHEL {static} + + AKHORAHIL {static} + + DWAR {static} + + HOARMURATH {static} + + JI_INDUR {static} + + KHAMUL {static} + + MURAZOR {static} + + REN {static} + + UVATHA {static} + + valueOf(name : String) : NazgulName {static} + + values() : NazgulName[] {static} + } +} +Nazgul --> "-name" NazgulName +@enduml \ No newline at end of file diff --git a/mute-idiom/etc/mute-idiom.urm.puml b/mute-idiom/etc/mute-idiom.urm.puml new file mode 100644 index 000000000..d4efc2db1 --- /dev/null +++ b/mute-idiom/etc/mute-idiom.urm.puml @@ -0,0 +1,23 @@ +@startuml +package com.iluwatar.mute { + interface Resource { + } + class App { + + App() + - acquireResource() : Resource {static} + - closeResource(resource : Resource) {static} + + main(args : String[]) {static} + - useOfLoggedMute() {static} + - useOfMute() {static} + - utilizeResource(resource : Resource) {static} + } + class Mute { + - Mute() + + loggedMute(runnable : CheckedRunnable) {static} + + mute(runnable : CheckedRunnable) {static} + } + interface CheckedRunnable { + + run() {abstract} + } +} +@enduml \ No newline at end of file diff --git a/mutex/etc/mutex.urm.puml b/mutex/etc/mutex.urm.puml new file mode 100644 index 000000000..24ea83630 --- /dev/null +++ b/mutex/etc/mutex.urm.puml @@ -0,0 +1,27 @@ +@startuml +package com.iluwatar.mutex { + interface Lock { + + acquire() {abstract} + + release() {abstract} + } + class Mutex { + - owner : Object + + Mutex() + + acquire() + + getOwner() : Object + + release() + } + class Jar { + - beans : int + - lock : Lock + + Jar(beans : int, lock : Lock) + + takeBean() : boolean + } + class App { + + App() + + main(args : String[]) {static} + } +} +Jar --> "-lock" Lock +Mutex ..|> Lock +@enduml \ No newline at end of file diff --git a/naked-objects/etc/naked-objects-dom.urm.puml b/naked-objects/etc/naked-objects-dom.urm.puml new file mode 100644 index 000000000..ea32b5787 --- /dev/null +++ b/naked-objects/etc/naked-objects-dom.urm.puml @@ -0,0 +1,84 @@ +@startuml +package domainapp.dom.app.homepage { + class HomePageViewModel { + ~ simpleObjects : SimpleObjects + + HomePageViewModel() + + getObjects() : List + + title() : String + } + class HomePageService { + ~ container : DomainObjectContainer + + HomePageService() + + homePage() : HomePageViewModel + } +} +package domainapp.dom.modules.simple { + class SimpleObjects { + ~ container : DomainObjectContainer + + SimpleObjects() + + create(name : String) : SimpleObject + + findByName(name : String) : List + + listAll() : List + + title() : TranslatableString + } + class SimpleObject { + - container : DomainObjectContainer + - dnFieldFlags : byte[] {static} + - dnFieldNames : String[] {static} + - dnFieldTypes : Class[] {static} + # dnFlags : byte + - dnInheritedFieldCount : int {static} + - dnPersistableSuperclass : Class {static} + # dnStateManager : StateManager + - name : String + + SimpleObject() + + ___dn$loadClass(className : String) : Class {static} + - __dnFieldFlagsInit() : byte[] {static} + - __dnFieldNamesInit() : String[] {static} + - __dnFieldTypesInit() : Class[] {static} + # __dnGetInheritedFieldCount() : int {static} + - __dnPersistableSuperclassInit() : Class {static} + + compareTo(other : SimpleObject) : int + + default0UpdateName() : String + # dnCopyField(obj : SimpleObject, index : int) + + dnCopyFields(obj : Object, indices : int[]) + + dnCopyKeyFieldsFromObjectId(fc : ObjectIdFieldConsumer, oid : Object) + # dnCopyKeyFieldsFromObjectId(oid : Object) + + dnCopyKeyFieldsToObjectId(fs : ObjectIdFieldSupplier, oid : Object) + + dnCopyKeyFieldsToObjectId(oid : Object) + + dnGetExecutionContext() : ExecutionContextReference + # dnGetManagedFieldCount() : int {static} + + dnGetObjectId() : Object + + dnGetTransactionalObjectId() : Object + + dnGetVersion() : Object + + dnGetname() : String + + dnIsDeleted() : boolean + + dnIsDetached() : boolean + + dnIsDirty() : boolean + + dnIsNew() : boolean + + dnIsPersistent() : boolean + + dnIsTransactional() : boolean + + dnMakeDirty(fieldName : String) + + dnNewInstance(sm : StateManager) : Persistable + + dnNewInstance(sm : StateManager, obj : Object) : Persistable + + dnNewObjectIdInstance() : Object + + dnNewObjectIdInstance(key : Object) : Object + # dnPreSerialize() + + dnProvideField(index : int) + + dnProvideFields(indices : int[]) + + dnReplaceField(index : int) + + dnReplaceFields(indices : int[]) + + dnReplaceFlags() + + dnReplaceStateManager(sm : StateManager) + + dnSetname(name : String) + - dnSuperClone() : Object + + getName() : String + + getVersionSequence() : Long + + setName(val : String) + + title() : TranslatableString + + updateName(name : String) : SimpleObject + + validateUpdateName(name : String) : TranslatableString + } +} +HomePageViewModel --> "-simpleObjects" SimpleObjects +@enduml \ No newline at end of file diff --git a/naked-objects/etc/naked-objects-fixture.urm.puml b/naked-objects/etc/naked-objects-fixture.urm.puml new file mode 100644 index 000000000..65c44410a --- /dev/null +++ b/naked-objects/etc/naked-objects-fixture.urm.puml @@ -0,0 +1,92 @@ +@startuml +package domainapp.dom.app.homepage { + class HomePageViewModel { + ~ simpleObjects : SimpleObjects + + HomePageViewModel() + + getObjects() : List + + title() : String + } + class HomePageService { + ~ container : DomainObjectContainer + + HomePageService() + + homePage() : HomePageViewModel + } +} +package domainapp.dom.modules.simple { + class SimpleObject { + - container : DomainObjectContainer + - dnFieldFlags : byte[] {static} + - dnFieldNames : String[] {static} + - dnFieldTypes : Class[] {static} + # dnFlags : byte + - dnInheritedFieldCount : int {static} + - dnPersistableSuperclass : Class {static} + # dnStateManager : StateManager + - name : String + + SimpleObject() + + ___dn$loadClass(className : String) : Class {static} + - __dnFieldFlagsInit() : byte[] {static} + - __dnFieldNamesInit() : String[] {static} + - __dnFieldTypesInit() : Class[] {static} + # __dnGetInheritedFieldCount() : int {static} + - __dnPersistableSuperclassInit() : Class {static} + + compareTo(other : SimpleObject) : int + + default0UpdateName() : String + # dnCopyField(obj : SimpleObject, index : int) + + dnCopyFields(obj : Object, indices : int[]) + + dnCopyKeyFieldsFromObjectId(fc : ObjectIdFieldConsumer, oid : Object) + # dnCopyKeyFieldsFromObjectId(oid : Object) + + dnCopyKeyFieldsToObjectId(fs : ObjectIdFieldSupplier, oid : Object) + + dnCopyKeyFieldsToObjectId(oid : Object) + + dnGetExecutionContext() : ExecutionContextReference + # dnGetManagedFieldCount() : int {static} + + dnGetObjectId() : Object + + dnGetTransactionalObjectId() : Object + + dnGetVersion() : Object + + dnGetname() : String + + dnIsDeleted() : boolean + + dnIsDetached() : boolean + + dnIsDirty() : boolean + + dnIsNew() : boolean + + dnIsPersistent() : boolean + + dnIsTransactional() : boolean + + dnMakeDirty(fieldName : String) + + dnNewInstance(sm : StateManager) : Persistable + + dnNewInstance(sm : StateManager, obj : Object) : Persistable + + dnNewObjectIdInstance() : Object + + dnNewObjectIdInstance(key : Object) : Object + # dnPreSerialize() + + dnProvideField(index : int) + + dnProvideFields(indices : int[]) + + dnReplaceField(index : int) + + dnReplaceFields(indices : int[]) + + dnReplaceFlags() + + dnReplaceStateManager(sm : StateManager) + + dnSetname(name : String) + - dnSuperClone() : Object + + getName() : String + + getVersionSequence() : Long + + setName(val : String) + + title() : TranslatableString + + updateName(name : String) : SimpleObject + + validateUpdateName(name : String) : TranslatableString + } + class SimpleObjects { + ~ container : DomainObjectContainer + + SimpleObjects() + + create(name : String) : SimpleObject + + findByName(name : String) : List + + listAll() : List + + title() : TranslatableString + } +} +package domainapp.fixture { + class DomainAppFixturesProvider { + + DomainAppFixturesProvider() + + getSpecification() : FixtureScriptsSpecification + } +} +DomainAppFixturesProvider --+ FixtureScripts +DomainAppFixturesProvider --+ FixtureScriptsSpecification +HomePageViewModel --> "-simpleObjects" SimpleObjects +@enduml \ No newline at end of file diff --git a/naked-objects/etc/naked-objects-integtests.urm.puml b/naked-objects/etc/naked-objects-integtests.urm.puml new file mode 100644 index 000000000..1f2dfc4c2 --- /dev/null +++ b/naked-objects/etc/naked-objects-integtests.urm.puml @@ -0,0 +1,92 @@ +@startuml +package domainapp.dom.app.homepage { + class HomePageService { + ~ container : DomainObjectContainer + + HomePageService() + + homePage() : HomePageViewModel + } + class HomePageViewModel { + ~ simpleObjects : SimpleObjects + + HomePageViewModel() + + getObjects() : List + + title() : String + } +} +package domainapp.dom.modules.simple { + class SimpleObjects { + ~ container : DomainObjectContainer + + SimpleObjects() + + create(name : String) : SimpleObject + + findByName(name : String) : List + + listAll() : List + + title() : TranslatableString + } + class SimpleObject { + - container : DomainObjectContainer + - dnFieldFlags : byte[] {static} + - dnFieldNames : String[] {static} + - dnFieldTypes : Class[] {static} + # dnFlags : byte + - dnInheritedFieldCount : int {static} + - dnPersistableSuperclass : Class {static} + # dnStateManager : StateManager + - name : String + + SimpleObject() + + ___dn$loadClass(className : String) : Class {static} + - __dnFieldFlagsInit() : byte[] {static} + - __dnFieldNamesInit() : String[] {static} + - __dnFieldTypesInit() : Class[] {static} + # __dnGetInheritedFieldCount() : int {static} + - __dnPersistableSuperclassInit() : Class {static} + + compareTo(other : SimpleObject) : int + + default0UpdateName() : String + # dnCopyField(obj : SimpleObject, index : int) + + dnCopyFields(obj : Object, indices : int[]) + + dnCopyKeyFieldsFromObjectId(fc : ObjectIdFieldConsumer, oid : Object) + # dnCopyKeyFieldsFromObjectId(oid : Object) + + dnCopyKeyFieldsToObjectId(fs : ObjectIdFieldSupplier, oid : Object) + + dnCopyKeyFieldsToObjectId(oid : Object) + + dnGetExecutionContext() : ExecutionContextReference + # dnGetManagedFieldCount() : int {static} + + dnGetObjectId() : Object + + dnGetTransactionalObjectId() : Object + + dnGetVersion() : Object + + dnGetname() : String + + dnIsDeleted() : boolean + + dnIsDetached() : boolean + + dnIsDirty() : boolean + + dnIsNew() : boolean + + dnIsPersistent() : boolean + + dnIsTransactional() : boolean + + dnMakeDirty(fieldName : String) + + dnNewInstance(sm : StateManager) : Persistable + + dnNewInstance(sm : StateManager, obj : Object) : Persistable + + dnNewObjectIdInstance() : Object + + dnNewObjectIdInstance(key : Object) : Object + # dnPreSerialize() + + dnProvideField(index : int) + + dnProvideFields(indices : int[]) + + dnReplaceField(index : int) + + dnReplaceFields(indices : int[]) + + dnReplaceFlags() + + dnReplaceStateManager(sm : StateManager) + + dnSetname(name : String) + - dnSuperClone() : Object + + getName() : String + + getVersionSequence() : Long + + setName(val : String) + + title() : TranslatableString + + updateName(name : String) : SimpleObject + + validateUpdateName(name : String) : TranslatableString + } +} +package domainapp.fixture { + class DomainAppFixturesProvider { + + DomainAppFixturesProvider() + + getSpecification() : FixtureScriptsSpecification + } +} +DomainAppFixturesProvider --+ FixtureScripts +DomainAppFixturesProvider --+ FixtureScriptsSpecification +HomePageViewModel --> "-simpleObjects" SimpleObjects +@enduml \ No newline at end of file diff --git a/null-object/etc/null-object.urm.puml b/null-object/etc/null-object.urm.puml new file mode 100644 index 000000000..d0b2936c5 --- /dev/null +++ b/null-object/etc/null-object.urm.puml @@ -0,0 +1,40 @@ +@startuml +package com.iluwatar.nullobject { + class NullNode { + - instance : NullNode {static} + - NullNode() + + getInstance() : NullNode {static} + + getLeft() : Node + + getName() : String + + getRight() : Node + + getTreeSize() : int + + walk() + } + interface Node { + + getLeft() : Node {abstract} + + getName() : String {abstract} + + getRight() : Node {abstract} + + getTreeSize() : int {abstract} + + walk() {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class NodeImpl { + - left : Node + - name : String + - right : Node + + NodeImpl(name : String, left : Node, right : Node) + + getLeft() : Node + + getName() : String + + getRight() : Node + + getTreeSize() : int + + walk() + } +} +NullNode --> "-instance" NullNode +NodeImpl --> "-left" Node +NullNode ..|> Node +NodeImpl ..|> Node +@enduml \ No newline at end of file diff --git a/object-pool/etc/object-pool.urm.puml b/object-pool/etc/object-pool.urm.puml new file mode 100644 index 000000000..9df1081d3 --- /dev/null +++ b/object-pool/etc/object-pool.urm.puml @@ -0,0 +1,29 @@ +@startuml +package com.iluwatar.object.pool { + class Oliphaunt { + - counter : int {static} + - id : int + + Oliphaunt() + + getId() : int + + toString() : String + } + class OliphauntPool { + + OliphauntPool() + # create() : Oliphaunt + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class ObjectPool { + - available : HashSet + - inUse : HashSet + + ObjectPool() + + checkIn(instance : T) + + checkOut() : T + # create() : T {abstract} + + toString() : String + } +} +OliphauntPool --|> ObjectPool +@enduml \ No newline at end of file diff --git a/observer/etc/observer.urm.puml b/observer/etc/observer.urm.puml new file mode 100644 index 000000000..33485d731 --- /dev/null +++ b/observer/etc/observer.urm.puml @@ -0,0 +1,73 @@ +@startuml +package com.iluwatar.observer { + class Orcs { + + Orcs() + + update(currentWeather : WeatherType) + } + class Hobbits { + + Hobbits() + + update(currentWeather : WeatherType) + } + class Weather { + - currentWeather : WeatherType + - observers : List + + Weather() + + addObserver(obs : WeatherObserver) + - notifyObservers() + + removeObserver(obs : WeatherObserver) + + timePasses() + } + class App { + + App() + + main(args : String[]) {static} + } + interface WeatherObserver { + + update(WeatherType) {abstract} + } + enum WeatherType { + + COLD {static} + + RAINY {static} + + SUNNY {static} + + WINDY {static} + + toString() : String + + valueOf(name : String) : WeatherType {static} + + values() : WeatherType[] {static} + } +} +package com.iluwatar.observer.generic { + class GOrcs { + + GOrcs() + + update(weather : GWeather, weatherType : WeatherType) + } + interface Race { + } + abstract class Observable, A> { + # observers : List> + + Observable, A>() + + addObserver(observer : O extends Observer) + + notifyObservers(argument : A) + + removeObserver(observer : O extends Observer) + } + class GWeather { + - currentWeather : WeatherType + + GWeather() + + timePasses() + } + interface Observer, O extends Observer, A> { + + update(S extends Observable, A) {abstract} + } + class GHobbits { + + GHobbits() + + update(weather : GWeather, weatherType : WeatherType) + } +} +Weather --> "-currentWeather" WeatherType +GWeather --> "-currentWeather" WeatherType +Weather --> "-observers" WeatherObserver +GOrcs ..|> Race +Orcs ..|> WeatherObserver +Hobbits ..|> WeatherObserver +Race --|> Observer +GWeather --|> Observable +GHobbits ..|> Race +@enduml \ No newline at end of file diff --git a/page-object/etc/page-object.urm.puml b/page-object/etc/page-object.urm.puml new file mode 100644 index 000000000..735cf2889 --- /dev/null +++ b/page-object/etc/page-object.urm.puml @@ -0,0 +1,8 @@ +@startuml +package com.iluwatar.pageobject { + class App { + - App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/poison-pill/etc/poison-pill.urm.puml b/poison-pill/etc/poison-pill.urm.puml new file mode 100644 index 000000000..58f9eb937 --- /dev/null +++ b/poison-pill/etc/poison-pill.urm.puml @@ -0,0 +1,72 @@ +@startuml +package com.iluwatar.poison.pill { + interface Message { + + POISON_PILL : Message {static} + + addHeader(Headers, String) {abstract} + + getBody() : String {abstract} + + getHeader(Headers) : String {abstract} + + getHeaders() : Map {abstract} + + setBody(String) {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class SimpleMessage { + - body : String + - headers : Map + + SimpleMessage() + + addHeader(header : Headers, value : String) + + getBody() : String + + getHeader(header : Headers) : String + + getHeaders() : Map + + setBody(body : String) + } + class SimpleMessageQueue { + - queue : BlockingQueue + + SimpleMessageQueue(bound : int) + + put(msg : Message) + + take() : Message + } + class Producer { + - isStopped : boolean + - name : String + - queue : MqPublishPoint + + Producer(name : String, queue : MqPublishPoint) + + send(body : String) + + stop() + } + interface MqSubscribePoint { + + take() : Message {abstract} + } + class Consumer { + - name : String + - queue : MqSubscribePoint + + Consumer(name : String, queue : MqSubscribePoint) + + consume() + } + interface MessageQueue { + } + interface MqPublishPoint { + + put(Message) {abstract} + } + enum Headers { + + DATE {static} + + SENDER {static} + + valueOf(name : String) : Headers {static} + + values() : Headers[] {static} + } +} +SimpleMessageQueue --> "-queue" Message +Headers ..+ Message +Consumer --> "-queue" MqSubscribePoint +Producer --> "-queue" MqPublishPoint +SimpleMessage --+ Message +Producer --+ Message +Message --> "-POISON_PILL" Message +Consumer --+ Message +SimpleMessage ..|> Message +SimpleMessageQueue ..|> MessageQueue +MessageQueue --|> MqPublishPoint +MessageQueue --|> MqSubscribePoint +@enduml \ No newline at end of file diff --git a/private-class-data/etc/private-class-data.urm.puml b/private-class-data/etc/private-class-data.urm.puml new file mode 100644 index 000000000..0edc2c1a8 --- /dev/null +++ b/private-class-data/etc/private-class-data.urm.puml @@ -0,0 +1,34 @@ +@startuml +package com.iluwatar.privateclassdata { + class Stew { + - numCarrots : int + - numMeat : int + - numPeppers : int + - numPotatoes : int + + Stew(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) + + mix() + + taste() + } + class App { + + App() + + main(args : String[]) {static} + } + class StewData { + - numCarrots : int + - numMeat : int + - numPeppers : int + - numPotatoes : int + + StewData(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) + + getNumCarrots() : int + + getNumMeat() : int + + getNumPeppers() : int + + getNumPotatoes() : int + } + class ImmutableStew { + - data : StewData + + ImmutableStew(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) + + mix() + } +} +ImmutableStew --> "-data" StewData +@enduml \ No newline at end of file diff --git a/producer-consumer/etc/producer-consumer.urm.puml b/producer-consumer/etc/producer-consumer.urm.puml new file mode 100644 index 000000000..9a6748552 --- /dev/null +++ b/producer-consumer/etc/producer-consumer.urm.puml @@ -0,0 +1,37 @@ +@startuml +package com.iluwatar.producer.consumer { + class Producer { + - itemId : int + - name : String + - queue : ItemQueue + + Producer(name : String, queue : ItemQueue) + + produce() + } + class ItemQueue { + - queue : BlockingQueue + + ItemQueue() + + put(item : Item) + + take() : Item + } + class Item { + - id : int + - producer : String + + Item(producer : String, id : int) + + getId() : int + + getProducer() : String + } + class App { + + App() + + main(args : String[]) {static} + } + class Consumer { + - name : String + - queue : ItemQueue + + Consumer(name : String, queue : ItemQueue) + + consume() + } +} +Consumer --> "-queue" ItemQueue +Producer --> "-queue" ItemQueue +ItemQueue --> "-queue" Item +@enduml \ No newline at end of file diff --git a/property/etc/property.urm.puml b/property/etc/property.urm.puml new file mode 100644 index 000000000..7c90edccc --- /dev/null +++ b/property/etc/property.urm.puml @@ -0,0 +1,54 @@ +@startuml +package com.iluwatar.property { + class Character { + - name : String + - properties : Map + - prototype : Prototype + - type : Type + + Character() + + Character(name : String, prototype : Character) + + Character(type : Type, prototype : Prototype) + + get(stat : Stats) : Integer + + has(stat : Stats) : boolean + + name() : String + + remove(stat : Stats) + + set(stat : Stats, val : Integer) + + toString() : String + + type() : Type + } + interface Prototype { + + get(Stats) : Integer {abstract} + + has(Stats) : boolean {abstract} + + remove(Stats) {abstract} + + set(Stats, Integer) {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + enum Stats { + + AGILITY {static} + + ARMOR {static} + + ATTACK_POWER {static} + + ENERGY {static} + + INTELLECT {static} + + RAGE {static} + + SPIRIT {static} + + STRENGTH {static} + + valueOf(name : String) : Stats {static} + + values() : Stats[] {static} + } + enum Type { + + MAGE {static} + + ROGUE {static} + + WARRIOR {static} + + valueOf(name : String) : Type {static} + + values() : Type[] {static} + } +} +App --+ Character +Character --> "-prototype" Prototype +Character --> "-type" Type +Type ..+ Character +Character ..|> Prototype +@enduml \ No newline at end of file diff --git a/prototype/etc/prototype.urm.puml b/prototype/etc/prototype.urm.puml new file mode 100644 index 000000000..7bfc00e15 --- /dev/null +++ b/prototype/etc/prototype.urm.puml @@ -0,0 +1,81 @@ +@startuml +package com.iluwatar.prototype { + interface HeroFactory { + + createBeast() : Beast {abstract} + + createMage() : Mage {abstract} + + createWarlord() : Warlord {abstract} + } + class OrcBeast { + + OrcBeast() + + clone() : Beast + + toString() : String + } + abstract class Mage { + + Mage() + + clone() : Mage {abstract} + } + class HeroFactoryImpl { + - beast : Beast + - mage : Mage + - warlord : Warlord + + HeroFactoryImpl(mage : Mage, warlord : Warlord, beast : Beast) + + createBeast() : Beast + + createMage() : Mage + + createWarlord() : Warlord + } + class ElfMage { + + ElfMage() + + clone() : Mage + + toString() : String + } + abstract class Prototype { + + Prototype() + + clone() : Object {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class Warlord { + + Warlord() + + clone() : Warlord {abstract} + } + class OrcWarlord { + + OrcWarlord() + + clone() : Warlord + + toString() : String + } + class ElfWarlord { + + ElfWarlord() + + clone() : Warlord + + toString() : String + } + abstract class Beast { + + Beast() + + clone() : Beast {abstract} + } + class OrcMage { + + OrcMage() + + clone() : Mage + + toString() : String + } + class ElfBeast { + + ElfBeast() + + clone() : Beast + + toString() : String + } +} +HeroFactoryImpl --> "-beast" Beast +HeroFactoryImpl --> "-warlord" Warlord +HeroFactoryImpl --> "-mage" Mage +OrcBeast --|> Beast +Mage --|> Prototype +HeroFactoryImpl ..|> HeroFactory +ElfMage --|> Mage +Warlord --|> Prototype +OrcWarlord --|> Warlord +ElfWarlord --|> Warlord +Beast --|> Prototype +OrcMage --|> Mage +ElfBeast --|> Beast +@enduml \ No newline at end of file diff --git a/proxy/etc/proxy.urm.puml b/proxy/etc/proxy.urm.puml new file mode 100644 index 000000000..4203174de --- /dev/null +++ b/proxy/etc/proxy.urm.puml @@ -0,0 +1,24 @@ +@startuml +package com.iluwatar.proxy { + class WizardTower { + + WizardTower() + + enter(wizard : Wizard) + } + class App { + + App() + + main(args : String[]) {static} + } + class WizardTowerProxy { + - NUM_WIZARDS_ALLOWED : int {static} + - numWizards : int + + WizardTowerProxy() + + enter(wizard : Wizard) + } + class Wizard { + - name : String + + Wizard(name : String) + + toString() : String + } +} +WizardTowerProxy --|> WizardTower +@enduml \ No newline at end of file diff --git a/publish-subscribe/etc/publish-subscribe.urm.puml b/publish-subscribe/etc/publish-subscribe.urm.puml new file mode 100644 index 000000000..1272f1f6d --- /dev/null +++ b/publish-subscribe/etc/publish-subscribe.urm.puml @@ -0,0 +1,8 @@ +@startuml +package com.iluwatar.publish.subscribe { + class App { + + App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/reactor/etc/reactor.urm.puml b/reactor/etc/reactor.urm.puml new file mode 100644 index 000000000..302f2663c --- /dev/null +++ b/reactor/etc/reactor.urm.puml @@ -0,0 +1,151 @@ +@startuml +package com.iluwatar.reactor.app { + ~class TcpLoggingClient { + - clientName : String + - serverPort : int + + TcpLoggingClient(clientName : String, serverPort : int) + + run() + - sendLogRequests(writer : PrintWriter, inputStream : InputStream) + } + ~class UdpLoggingClient { + - clientName : String + - remoteAddress : InetSocketAddress + + UdpLoggingClient(clientName : String, port : int) + + run() + } + class LoggingHandler { + - ACK : byte[] {static} + + LoggingHandler() + - doLogging(data : ByteBuffer) {static} + + handleChannelRead(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + - sendReply(channel : AbstractNioChannel, incomingPacket : DatagramPacket, key : SelectionKey) {static} + - sendReply(channel : AbstractNioChannel, key : SelectionKey) {static} + } + class AppClient { + - service : ExecutorService + + AppClient() + - artificialDelayOf(millis : long) {static} + + main(args : String[]) {static} + + start() + + stop() + } + class App { + - channels : List + - dispatcher : Dispatcher + - reactor : NioReactor + + App(dispatcher : Dispatcher) + + main(args : String[]) {static} + + start() + + stop() + - tcpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel + - udpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel + } +} +package com.iluwatar.reactor.framework { + interface Dispatcher { + + onChannelReadEvent(AbstractNioChannel, Object, SelectionKey) {abstract} + + stop() {abstract} + } + class SameThreadDispatcher { + + SameThreadDispatcher() + + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + + stop() + } + class ThreadPoolDispatcher { + - executorService : ExecutorService + + ThreadPoolDispatcher(poolSize : int) + + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + + stop() + } + interface ChannelHandler { + + handleChannelRead(AbstractNioChannel, Object, SelectionKey) {abstract} + } + class NioDatagramChannel { + - port : int + + NioDatagramChannel(port : int, handler : ChannelHandler) + + bind() + # doWrite(pendingWrite : Object, key : SelectionKey) + + getInterestedOps() : int + + getJavaChannel() : DatagramChannel + + read(key : SelectionKey) : DatagramPacket + + write(data : Object, key : SelectionKey) + } + class DatagramPacket { + - data : ByteBuffer + - receiver : SocketAddress + - sender : SocketAddress + + DatagramPacket(data : ByteBuffer) + + getData() : ByteBuffer + + getReceiver() : SocketAddress + + getSender() : SocketAddress + + setReceiver(receiver : SocketAddress) + + setSender(sender : SocketAddress) + } + abstract class AbstractNioChannel { + - channel : SelectableChannel + - channelToPendingWrites : Map> + - handler : ChannelHandler + - reactor : NioReactor + + AbstractNioChannel(handler : ChannelHandler, channel : SelectableChannel) + + bind() {abstract} + # doWrite(Object, SelectionKey) {abstract} + ~ flush(key : SelectionKey) + + getHandler() : ChannelHandler + + getInterestedOps() : int {abstract} + + getJavaChannel() : SelectableChannel + + read(SelectionKey) : Object {abstract} + ~ setReactor(reactor : NioReactor) + + write(data : Object, key : SelectionKey) + } + class NioServerSocketChannel { + - port : int + + NioServerSocketChannel(port : int, handler : ChannelHandler) + + bind() + # doWrite(pendingWrite : Object, key : SelectionKey) + + getInterestedOps() : int + + getJavaChannel() : ServerSocketChannel + + read(key : SelectionKey) : ByteBuffer + } + class NioReactor { + - dispatcher : Dispatcher + - pendingCommands : Queue + - reactorMain : ExecutorService + - selector : Selector + + NioReactor(dispatcher : Dispatcher) + + changeOps(key : SelectionKey, interestedOps : int) + - dispatchReadEvent(key : SelectionKey, readObject : Object) + - eventLoop() + - onChannelAcceptable(key : SelectionKey) + - onChannelReadable(key : SelectionKey) + - onChannelWritable(key : SelectionKey) {static} + - processKey(key : SelectionKey) + - processPendingCommands() + + registerChannel(channel : AbstractNioChannel) : NioReactor + + start() + + stop() + } + ~class ChangeKeyOpsCommand { + - interestedOps : int + - key : SelectionKey + + ChangeKeyOpsCommand(this$0 : NioReactor, key : SelectionKey, interestedOps : int) + + run() + + toString() : String + } +} +AbstractNioChannel --> "-handler" ChannelHandler +UdpLoggingClient ..+ AppClient +AbstractNioChannel --> "-reactor" NioReactor +TcpLoggingClient ..+ AppClient +NioReactor --> "-dispatcher" Dispatcher +App --> "-reactor" NioReactor +App --> "-channels" AbstractNioChannel +DatagramPacket ..+ NioDatagramChannel +ChangeKeyOpsCommand --+ NioReactor +App --> "-dispatcher" Dispatcher +LoggingHandler --+ NioDatagramChannel +SameThreadDispatcher ..|> Dispatcher +LoggingHandler ..|> ChannelHandler +ThreadPoolDispatcher ..|> Dispatcher +NioDatagramChannel --|> AbstractNioChannel +NioServerSocketChannel --|> AbstractNioChannel +@enduml \ 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 new file mode 100644 index 000000000..22b303cf5 --- /dev/null +++ b/reader-writer-lock/etc/reader-writer-lock.urm.puml @@ -0,0 +1,58 @@ +@startuml +package com.iluwatar.reader.writer.lock { + -class ReadLock { + - ReadLock(ReaderWriterLock) + + lock() + + lockInterruptibly() + + newCondition() : Condition + + tryLock() : boolean + + tryLock(time : long, unit : TimeUnit) : boolean + + unlock() + } + class Writer { + - name : String + - writeLock : Lock + + Writer(name : String, writeLock : Lock) + + run() + + write() + } + class ReaderWriterLock { + - currentReaderCount : int + - globalMutex : Set + - readerLock : ReadLock + - readerMutex : Object + - writerLock : WriteLock + + ReaderWriterLock() + - doesReaderOwnThisLock() : boolean + - doesWriterOwnThisLock() : boolean + - isLockFree() : boolean + + readLock() : Lock + - waitUninterruptibly(o : Object) {static} + + writeLock() : Lock + } + -class WriteLock { + - WriteLock(ReaderWriterLock) + + lock() + + lockInterruptibly() + + newCondition() : Condition + + tryLock() : boolean + + tryLock(time : long, unit : TimeUnit) : boolean + + unlock() + } + class App { + + App() + + main(args : String[]) {static} + } + class Reader { + - name : String + - readLock : Lock + + Reader(name : String, readLock : Lock) + + read() + + run() + } +} +ReadLock --+ ReaderWriterLock +ReaderWriterLock --> "-readerLock" ReadLock +ReaderWriterLock --> "-writerLock" WriteLock +WriteLock --+ ReaderWriterLock +@enduml \ No newline at end of file diff --git a/repository/etc/repository.urm.puml b/repository/etc/repository.urm.puml new file mode 100644 index 000000000..49a2c8fdc --- /dev/null +++ b/repository/etc/repository.urm.puml @@ -0,0 +1,56 @@ +@startuml +package com.iluwatar.repository { + class App { + + App() + + main(args : String[]) {static} + } + class Person { + - age : int + - id : Long + - name : String + - surname : String + + Person() + + Person(name : String, surname : String, age : int) + + equals(obj : Object) : boolean + + getAge() : int + + getId() : Long + + getName() : String + + getSurname() : String + + hashCode() : int + + setAge(age : int) + + setId(id : Long) + + setName(name : String) + + setSurname(surname : String) + + toString() : String + } + class AgeBetweenSpec { + - from : int + - to : int + + AgeBetweenSpec(from : int, to : int) + + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate + } + class AppConfig { + + AppConfig() + + dataSource() : DataSource + + entityManagerFactory() : LocalContainerEntityManagerFactoryBean + - jpaProperties() : Properties {static} + + main(args : String[]) {static} + + transactionManager() : JpaTransactionManager + } + interface PersonRepository { + + findByName(String) : Person {abstract} + } + class NameEqualSpec { + + name : String + + NameEqualSpec(name : String) + + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate + } + class PersonSpecifications { + + PersonSpecifications() + } +} +App --+ PersonSpecifications +AppConfig --+ PersonSpecifications +NameEqualSpec ..+ PersonSpecifications +AgeBetweenSpec ..+ PersonSpecifications +@enduml \ No newline at end of file diff --git a/resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml b/resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml new file mode 100644 index 000000000..847b716a0 --- /dev/null +++ b/resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml @@ -0,0 +1,16 @@ +@startuml +package com.iluwatar.resource.acquisition.is.initialization { + class App { + + App() + + main(args : String[]) {static} + } + class TreasureChest { + + TreasureChest() + + close() + } + class SlidingDoor { + + SlidingDoor() + + close() + } +} +@enduml \ No newline at end of file diff --git a/semaphore/etc/semaphore.urm.puml b/semaphore/etc/semaphore.urm.puml new file mode 100644 index 000000000..f85fff921 --- /dev/null +++ b/semaphore/etc/semaphore.urm.puml @@ -0,0 +1,58 @@ +@startuml +package com.iluwatar.semaphore { + class FruitShop { + - available : boolean[] + - bowls : FruitBowl[] + - semaphore : Semaphore + + FruitShop() + + countFruit() : int + + returnBowl(bowl : FruitBowl) + + takeBowl() : FruitBowl + } + class FruitBowl { + - fruit : ArrayList + + FruitBowl() + + countFruit() : int + + put(f : Fruit) + + take() : Fruit + + toString() : String + } + class Fruit { + - type : FruitType + + Fruit(type : FruitType) + + getType() : FruitType + + toString() : String + } + interface Lock { + + acquire() {abstract} + + release() {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class Semaphore { + - counter : int + - licenses : int + + Semaphore(licenses : int) + + acquire() + + getAvailableLicenses() : int + + getNumLicenses() : int + + release() + } + enum FruitType { + + APPLE {static} + + LEMON {static} + + ORANGE {static} + + valueOf(name : String) : FruitType {static} + + values() : FruitType[] {static} + } +} +FruitShop --+ Fruit +Fruit --> "-type" FruitType +FruitType ..+ Fruit +FruitBowl --+ Fruit +FruitBowl --> "-fruit" Fruit +FruitShop --> "-semaphore" Semaphore +Semaphore ..|> Lock +@enduml \ No newline at end of file diff --git a/servant/etc/servant.urm.puml b/servant/etc/servant.urm.puml new file mode 100644 index 000000000..48d48bd84 --- /dev/null +++ b/servant/etc/servant.urm.puml @@ -0,0 +1,55 @@ +@startuml +package com.iluwatar.servant { + class King { + - complimentReceived : boolean + - isDrunk : boolean + - isHappy : boolean + - isHungry : boolean + + King() + + changeMood() + + getDrink() + + getFed() + + getMood() : boolean + + receiveCompliments() + } + ~interface Royalty { + + changeMood() {abstract} + + getDrink() {abstract} + + getFed() {abstract} + + getMood() : boolean {abstract} + + receiveCompliments() {abstract} + } + class Servant { + + name : String + + Servant(name : String) + + checkIfYouWillBeHanged(tableGuests : List) : boolean + + feed(r : Royalty) + + giveCompliments(r : Royalty) + + giveWine(r : Royalty) + } + class Queen { + - complimentReceived : boolean + - isDrunk : boolean + - isFlirty : boolean + - isHappy : boolean + - isHungry : boolean + + Queen() + + changeMood() + + getDrink() + + getFed() + + getMood() : boolean + + receiveCompliments() + + setFlirtiness(f : boolean) + } + class App { + ~ jenkins : Servant {static} + ~ travis : Servant {static} + + App() + + main(args : String[]) {static} + + scenario(servant : Servant, compliment : int) {static} + } +} +App --> "-jenkins" Servant +King ..|> Royalty +Queen ..|> Royalty +@enduml \ No newline at end of file diff --git a/service-layer/etc/service-layer.urm.puml b/service-layer/etc/service-layer.urm.puml new file mode 100644 index 000000000..c67ffa645 --- /dev/null +++ b/service-layer/etc/service-layer.urm.puml @@ -0,0 +1,158 @@ +@startuml +package com.iluwatar.servicelayer.hibernate { + class HibernateUtil { + - sessionFactory : SessionFactory {static} + - HibernateUtil() + + dropSession() {static} + + getSessionFactory() : SessionFactory {static} + } +} +package com.iluwatar.servicelayer.common { + abstract class BaseEntity { + - version : Long + + BaseEntity() + + getId() : Long {abstract} + + getName() : String {abstract} + + setId(Long) {abstract} + + setName(String) {abstract} + } + interface Dao { + + delete(E extends BaseEntity) {abstract} + + find(Long) : E extends BaseEntity {abstract} + + findAll() : List {abstract} + + merge(E extends BaseEntity) : E extends BaseEntity {abstract} + + persist(E extends BaseEntity) {abstract} + } + abstract class DaoBaseImpl { + # persistentClass : Class + + DaoBaseImpl() + + delete(entity : E extends BaseEntity) + + find(id : Long) : E extends BaseEntity + + findAll() : List + # getSession() : Session + + merge(entity : E extends BaseEntity) : E extends BaseEntity + + persist(entity : E extends BaseEntity) + } +} +package com.iluwatar.servicelayer.magic { + interface MagicService { + + findAllSpellbooks() : List {abstract} + + findAllSpells() : List {abstract} + + findAllWizards() : List {abstract} + + findWizardsWithSpell(String) : List {abstract} + + findWizardsWithSpellbook(String) : List {abstract} + } + class MagicServiceImpl { + - spellDao : SpellDao + - spellbookDao : SpellbookDao + - wizardDao : WizardDao + + MagicServiceImpl(wizardDao : WizardDao, spellbookDao : SpellbookDao, spellDao : SpellDao) + + findAllSpellbooks() : List + + findAllSpells() : List + + findAllWizards() : List + + findWizardsWithSpell(name : String) : List + + findWizardsWithSpellbook(name : String) : List + } +} +package com.iluwatar.servicelayer.wizard { + class Wizard { + - id : Long + - name : String + - spellbooks : Set + + Wizard() + + Wizard(name : String) + + addSpellbook(spellbook : Spellbook) + + getId() : Long + + getName() : String + + getSpellbooks() : Set + + setId(id : Long) + + setName(name : String) + + setSpellbooks(spellbooks : Set) + + toString() : String + } + class WizardDaoImpl { + + WizardDaoImpl() + + findByName(name : String) : Wizard + } + interface WizardDao { + + findByName(String) : Wizard {abstract} + } +} +package com.iluwatar.servicelayer.app { + class App { + + App() + + initData() {static} + + main(args : String[]) {static} + + queryData() {static} + } +} +package com.iluwatar.servicelayer.spell { + class SpellDaoImpl { + + SpellDaoImpl() + + findByName(name : String) : Spell + } + class Spell { + - id : Long + - name : String + - spellbook : Spellbook + + Spell() + + Spell(name : String) + + getId() : Long + + getName() : String + + getSpellbook() : Spellbook + + setId(id : Long) + + setName(name : String) + + setSpellbook(spellbook : Spellbook) + + toString() : String + } + interface SpellDao { + + findByName(String) : Spell {abstract} + } +} +package com.iluwatar.servicelayer.spellbook { + interface SpellbookDao { + + findByName(String) : Spellbook {abstract} + } + class Spellbook { + - id : Long + - name : String + - spells : Set + - wizards : Set + + Spellbook() + + Spellbook(name : String) + + addSpell(spell : Spell) + + getId() : Long + + getName() : String + + getSpells() : Set + + getWizards() : Set + + setId(id : Long) + + setName(name : String) + + setSpells(spells : Set) + + setWizards(wizards : Set) + + toString() : String + } + class SpellbookDaoImpl { + + SpellbookDaoImpl() + + findByName(name : String) : Spellbook + } +} +MagicServiceImpl --> "-wizardDao" WizardDao +MagicServiceImpl --> "-spellbookDao" SpellbookDao +MagicServiceImpl --> "-spellDao" SpellDao +Spellbook --> "-spells" Spell +Spellbook --> "-wizards" Wizard +Wizard --|> BaseEntity +SpellbookDao --|> Dao +SpellDaoImpl ..|> SpellDao +SpellDaoImpl --|> DaoBaseImpl +MagicServiceImpl ..|> MagicService +DaoBaseImpl ..|> Dao +WizardDaoImpl ..|> WizardDao +WizardDaoImpl --|> DaoBaseImpl +Spellbook --|> BaseEntity +SpellbookDaoImpl ..|> SpellbookDao +SpellbookDaoImpl --|> DaoBaseImpl +Spell --|> BaseEntity +WizardDao --|> Dao +SpellDao --|> Dao +@enduml \ No newline at end of file diff --git a/service-locator/etc/service-locator.urm.puml b/service-locator/etc/service-locator.urm.puml new file mode 100644 index 000000000..085b05b28 --- /dev/null +++ b/service-locator/etc/service-locator.urm.puml @@ -0,0 +1,38 @@ +@startuml +package com.iluwatar.servicelocator { + interface Service { + + execute() {abstract} + + getId() : int {abstract} + + getName() : String {abstract} + } + class InitContext { + + InitContext() + + lookup(serviceName : String) : Object + } + class ServiceLocator { + - serviceCache : ServiceCache {static} + - ServiceLocator() + + getService(serviceJndiName : String) : Service {static} + } + class ServiceCache { + - serviceCache : Map + + ServiceCache() + + addService(newService : Service) + + getService(serviceName : String) : Service + } + class App { + + App() + + main(args : String[]) {static} + } + class ServiceImpl { + - id : int + - serviceName : String + + ServiceImpl(serviceName : String) + + execute() + + getId() : int + + getName() : String + } +} +ServiceLocator --> "-serviceCache" ServiceCache +ServiceImpl ..|> Service +@enduml \ No newline at end of file diff --git a/singleton/etc/singleton.urm.puml b/singleton/etc/singleton.urm.puml new file mode 100644 index 000000000..f5ec19879 --- /dev/null +++ b/singleton/etc/singleton.urm.puml @@ -0,0 +1,42 @@ +@startuml +package com.iluwatar.singleton { + class ThreadSafeLazyLoadedIvoryTower { + - instance : ThreadSafeLazyLoadedIvoryTower {static} + - ThreadSafeLazyLoadedIvoryTower() + + getInstance() : ThreadSafeLazyLoadedIvoryTower {static} + } + -class HelperHolder { + + INSTANCE : InitializingOnDemandHolderIdiom {static} + - HelperHolder() + } + class App { + + App() + + main(args : String[]) {static} + } + class ThreadSafeDoubleCheckLocking { + - instance : ThreadSafeDoubleCheckLocking {static} + - ThreadSafeDoubleCheckLocking() + + getInstance() : ThreadSafeDoubleCheckLocking {static} + } + class InitializingOnDemandHolderIdiom { + - InitializingOnDemandHolderIdiom() + + getInstance() : InitializingOnDemandHolderIdiom {static} + } + class IvoryTower { + - INSTANCE : IvoryTower {static} + - IvoryTower() + + getInstance() : IvoryTower {static} + } + enum EnumIvoryTower { + + INSTANCE {static} + + toString() : String + + valueOf(name : String) : EnumIvoryTower {static} + + values() : EnumIvoryTower[] {static} + } +} +IvoryTower --> "-INSTANCE" IvoryTower +ThreadSafeDoubleCheckLocking --> "-instance" ThreadSafeDoubleCheckLocking +ThreadSafeLazyLoadedIvoryTower --> "-instance" ThreadSafeLazyLoadedIvoryTower +HelperHolder ..+ InitializingOnDemandHolderIdiom +HelperHolder --> "-INSTANCE" InitializingOnDemandHolderIdiom +@enduml \ No newline at end of file diff --git a/specification/etc/specification.urm.puml b/specification/etc/specification.urm.puml new file mode 100644 index 000000000..0009a1bcd --- /dev/null +++ b/specification/etc/specification.urm.puml @@ -0,0 +1,106 @@ +@startuml +package com.iluwatar.specification.creature { + class Goblin { + + Goblin() + } + interface Creature { + + getColor() : Color {abstract} + + getMovement() : Movement {abstract} + + getName() : String {abstract} + + getSize() : Size {abstract} + } + class Troll { + + Troll() + } + abstract class AbstractCreature { + - color : Color + - movement : Movement + - name : String + - size : Size + + AbstractCreature(name : String, size : Size, movement : Movement, color : Color) + + getColor() : Color + + getMovement() : Movement + + getName() : String + + getSize() : Size + + toString() : String + } + class Shark { + + Shark() + } + class KillerBee { + + KillerBee() + } + class Octopus { + + Octopus() + } + class Dragon { + + Dragon() + } +} +package com.iluwatar.specification.property { + enum Color { + + DARK {static} + + GREEN {static} + + LIGHT {static} + + RED {static} + - title : String + + toString() : String + + valueOf(name : String) : Color {static} + + values() : Color[] {static} + } + enum Movement { + + FLYING {static} + + SWIMMING {static} + + WALKING {static} + - title : String + + toString() : String + + valueOf(name : String) : Movement {static} + + values() : Movement[] {static} + } + enum Size { + + LARGE {static} + + NORMAL {static} + + SMALL {static} + - title : String + + toString() : String + + valueOf(name : String) : Size {static} + + values() : Size[] {static} + } +} +package com.iluwatar.specification.app { + class App { + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.specification.selector { + class SizeSelector { + - s : Size + + SizeSelector(s : Size) + + test(t : Creature) : boolean + } + class ColorSelector { + - c : Color + + ColorSelector(c : Color) + + test(t : Creature) : boolean + } + class MovementSelector { + - m : Movement + + MovementSelector(m : Movement) + + test(t : Creature) : boolean + } +} +SizeSelector --> "-s" Size +AbstractCreature --> "-color" Color +MovementSelector --> "-m" Movement +AbstractCreature --> "-movement" Movement +AbstractCreature --> "-size" Size +ColorSelector --> "-c" Color +Goblin --|> AbstractCreature +Troll --|> AbstractCreature +AbstractCreature ..|> Creature +Shark --|> AbstractCreature +KillerBee --|> AbstractCreature +Octopus --|> AbstractCreature +Dragon --|> AbstractCreature +@enduml \ No newline at end of file diff --git a/state/etc/state.urm.puml b/state/etc/state.urm.puml new file mode 100644 index 000000000..a0951ff6e --- /dev/null +++ b/state/etc/state.urm.puml @@ -0,0 +1,37 @@ +@startuml +package com.iluwatar.state { + class AngryState { + - mammoth : Mammoth + + AngryState(mammoth : Mammoth) + + observe() + + onEnterState() + } + class Mammoth { + - state : State + + Mammoth() + - changeStateTo(newState : State) + + observe() + + timePasses() + + toString() : String + } + interface State { + + observe() {abstract} + + onEnterState() {abstract} + } + class PeacefulState { + - mammoth : Mammoth + + PeacefulState(mammoth : Mammoth) + + observe() + + onEnterState() + } + class App { + + App() + + main(args : String[]) {static} + } +} +PeacefulState --> "-mammoth" Mammoth +AngryState --> "-mammoth" Mammoth +Mammoth --> "-state" State +AngryState ..|> State +PeacefulState ..|> State +@enduml \ No newline at end of file diff --git a/step-builder/etc/step-builder.urm.puml b/step-builder/etc/step-builder.urm.puml new file mode 100644 index 000000000..cc1f88ef0 --- /dev/null +++ b/step-builder/etc/step-builder.urm.puml @@ -0,0 +1,91 @@ +@startuml +package com.iluwatar.stepbuilder { + interface BuildStep { + + build() : Character {abstract} + } + -class CharacterSteps { + - abilities : List + - fighterClass : String + - name : String + - spell : String + - weapon : String + - wizardClass : String + - CharacterSteps() + + build() : Character + + fighterClass(fighterClass : String) : WeaponStep + + name(name : String) : ClassStep + + noAbilities() : BuildStep + + noMoreAbilities() : BuildStep + + noSpell() : BuildStep + + noWeapon() : BuildStep + + withAbility(ability : String) : AbilityStep + + withSpell(spell : String) : AbilityStep + + withWeapon(weapon : String) : AbilityStep + + wizardClass(wizardClass : String) : SpellStep + } + class App { + + App() + + main(args : String[]) {static} + } + interface ClassStep { + + fighterClass(String) : WeaponStep {abstract} + + wizardClass(String) : SpellStep {abstract} + } + interface WeaponStep { + + noWeapon() : BuildStep {abstract} + + withWeapon(String) : AbilityStep {abstract} + } + interface AbilityStep { + + noAbilities() : BuildStep {abstract} + + noMoreAbilities() : BuildStep {abstract} + + withAbility(String) : AbilityStep {abstract} + } + interface NameStep { + + name(String) : ClassStep {abstract} + } + class CharacterStepBuilder { + - CharacterStepBuilder() + + newBuilder() : NameStep {static} + } + class Character { + - abilities : List + - fighterClass : String + - name : String + - spell : String + - weapon : String + - wizardClass : String + + Character(name : String) + + getAbilities() : List + + getFighterClass() : String + + getName() : String + + getSpell() : String + + getWeapon() : String + + getWizardClass() : String + + setAbilities(abilities : List) + + setFighterClass(fighterClass : String) + + setName(name : String) + + setSpell(spell : String) + + setWeapon(weapon : String) + + setWizardClass(wizardClass : String) + + toString() : String + } + interface SpellStep { + + noSpell() : BuildStep {abstract} + + withSpell(String) : AbilityStep {abstract} + } +} +App --+ CharacterStepBuilder +WeaponStep ..+ CharacterStepBuilder +SpellStep ..+ CharacterStepBuilder +AbilityStep ..+ CharacterStepBuilder +ClassStep ..+ CharacterStepBuilder +CharacterSteps ..+ CharacterStepBuilder +NameStep ..+ CharacterStepBuilder +BuildStep ..+ CharacterStepBuilder +CharacterSteps ..|> NameStep +CharacterSteps ..|> ClassStep +CharacterSteps ..|> WeaponStep +CharacterSteps ..|> SpellStep +CharacterSteps ..|> AbilityStep +CharacterSteps ..|> BuildStep +@enduml \ No newline at end of file diff --git a/strategy/etc/strategy.urm.puml b/strategy/etc/strategy.urm.puml new file mode 100644 index 000000000..2cc072863 --- /dev/null +++ b/strategy/etc/strategy.urm.puml @@ -0,0 +1,33 @@ +@startuml +package com.iluwatar.strategy { + class DragonSlayer { + - strategy : DragonSlayingStrategy + + DragonSlayer(strategy : DragonSlayingStrategy) + + changeStrategy(strategy : DragonSlayingStrategy) + + goToBattle() + } + class SpellStrategy { + + SpellStrategy() + + execute() + } + class ProjectileStrategy { + + ProjectileStrategy() + + execute() + } + interface DragonSlayingStrategy { + + execute() {abstract} + } + class MeleeStrategy { + + MeleeStrategy() + + execute() + } + class App { + + App() + + main(args : String[]) {static} + } +} +DragonSlayer --> "-strategy" DragonSlayingStrategy +SpellStrategy ..|> DragonSlayingStrategy +ProjectileStrategy ..|> DragonSlayingStrategy +MeleeStrategy ..|> DragonSlayingStrategy +@enduml \ No newline at end of file diff --git a/template-method/etc/template-method.urm.puml b/template-method/etc/template-method.urm.puml new file mode 100644 index 000000000..c98287bc6 --- /dev/null +++ b/template-method/etc/template-method.urm.puml @@ -0,0 +1,36 @@ +@startuml +package com.iluwatar.templatemethod { + class SubtleMethod { + + SubtleMethod() + # confuseTarget(target : String) + # pickTarget() : String + # stealTheItem(target : String) + } + class HitAndRunMethod { + + HitAndRunMethod() + # confuseTarget(target : String) + # pickTarget() : String + # stealTheItem(target : String) + } + abstract class StealingMethod { + + StealingMethod() + # confuseTarget(String) {abstract} + # pickTarget() : String {abstract} + + steal() + # stealTheItem(String) {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class HalflingThief { + - method : StealingMethod + + HalflingThief(method : StealingMethod) + + changeMethod(method : StealingMethod) + + steal() + } +} +HalflingThief --> "-method" StealingMethod +SubtleMethod --|> StealingMethod +HitAndRunMethod --|> StealingMethod +@enduml \ No newline at end of file diff --git a/thread-pool/etc/thread-pool.urm.puml b/thread-pool/etc/thread-pool.urm.puml new file mode 100644 index 000000000..2b73e2d53 --- /dev/null +++ b/thread-pool/etc/thread-pool.urm.puml @@ -0,0 +1,35 @@ +@startuml +package com.iluwatar.threadpool { + class Worker { + - task : Task + + Worker(task : Task) + + run() + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class Task { + - ID_GENERATOR : AtomicInteger {static} + - id : int + - timeMs : int + + Task(timeMs : int) + + getId() : int + + getTimeMs() : int + + toString() : String + } + class PotatoPeelingTask { + - TIME_PER_POTATO : int {static} + + PotatoPeelingTask(numPotatoes : int) + + toString() : String + } + class CoffeeMakingTask { + - TIME_PER_CUP : int {static} + + CoffeeMakingTask(numCups : int) + + toString() : String + } +} +Worker --> "-task" Task +PotatoPeelingTask --|> Task +CoffeeMakingTask --|> Task +@enduml \ No newline at end of file diff --git a/tolerant-reader/etc/tolerant-reader.urm.puml b/tolerant-reader/etc/tolerant-reader.urm.puml new file mode 100644 index 000000000..9e2bc83b3 --- /dev/null +++ b/tolerant-reader/etc/tolerant-reader.urm.puml @@ -0,0 +1,38 @@ +@startuml +package com.iluwatar.tolerantreader { + class RainbowFishSerializer { + - RainbowFishSerializer() + + readV1(filename : String) : RainbowFish {static} + + writeV1(rainbowFish : RainbowFish, filename : String) {static} + + writeV2(rainbowFish : RainbowFishV2, filename : String) {static} + } + class RainbowFish { + - age : int + - lengthMeters : int + - name : String + - serialVersionUID : long {static} + - weightTons : int + + RainbowFish(name : String, age : int, lengthMeters : int, weightTons : int) + + getAge() : int + + getLengthMeters() : int + + getName() : String + + getWeightTons() : int + } + class RainbowFishV2 { + - angry : boolean + - hungry : boolean + - serialVersionUID : long {static} + - sleeping : boolean + + RainbowFishV2(name : String, age : int, lengthMeters : int, weightTons : int) + + RainbowFishV2(name : String, age : int, lengthMeters : int, weightTons : int, sleeping : boolean, hungry : boolean, angry : boolean) + + getAngry() : boolean + + getHungry() : boolean + + getSleeping() : boolean + } + class App { + + App() + + main(args : String[]) {static} + } +} +RainbowFishV2 --|> RainbowFish +@enduml \ No newline at end of file diff --git a/twin/etc/twin.urm.puml b/twin/etc/twin.urm.puml new file mode 100644 index 000000000..b95325abb --- /dev/null +++ b/twin/etc/twin.urm.puml @@ -0,0 +1,25 @@ +@startuml +package com.iluwatar.twin { + class App { + + App() + + main(args : String[]) {static} + - waiting() {static} + } + class BallItem { + - isSuspended : boolean + - twin : BallThread + + BallItem() + + click() + + doDraw() + + move() + + setTwin(twin : BallThread) + } + abstract class GameItem { + + GameItem() + + click() {abstract} + + doDraw() {abstract} + + draw() + } +} +BallItem --|> GameItem +@enduml \ No newline at end of file diff --git a/value-object/etc/value-object.urm.puml b/value-object/etc/value-object.urm.puml new file mode 100644 index 000000000..223f91957 --- /dev/null +++ b/value-object/etc/value-object.urm.puml @@ -0,0 +1,21 @@ +@startuml +package com.iluwatar.value.object { + class App { + + App() + + main(args : String[]) {static} + } + class HeroStat { + - intelligence : int + - luck : int + - strength : int + - HeroStat(strength : int, intelligence : int, luck : int) + + equals(obj : Object) : boolean + + getIntelligence() : int + + getLuck() : int + + getStrength() : int + + hashCode() : int + + toString() : String + + valueOf(strength : int, intelligence : int, luck : int) : HeroStat {static} + } +} +@enduml \ No newline at end of file diff --git a/visitor/etc/visitor.urm.puml b/visitor/etc/visitor.urm.puml new file mode 100644 index 000000000..3f5689f71 --- /dev/null +++ b/visitor/etc/visitor.urm.puml @@ -0,0 +1,57 @@ +@startuml +package com.iluwatar.visitor { + class CommanderVisitor { + + CommanderVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } + class Sergeant { + + Sergeant(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + class Commander { + + Commander(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + abstract class Unit { + - children : Unit[] + + Unit(children : Unit[]) + + accept(visitor : UnitVisitor) + } + class Soldier { + + Soldier(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + class SergeantVisitor { + + SergeantVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } + interface UnitVisitor { + + visitCommander(Commander) {abstract} + + visitSergeant(Sergeant) {abstract} + + visitSoldier(Soldier) {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class SoldierVisitor { + + SoldierVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } +} +CommanderVisitor ..|> UnitVisitor +Sergeant --|> Unit +Commander --|> Unit +Soldier --|> Unit +SergeantVisitor ..|> UnitVisitor +SoldierVisitor ..|> UnitVisitor +@enduml \ No newline at end of file From 09037b0251cc949d13ce394462969dadb5655ce3 Mon Sep 17 00:00:00 2001 From: Markus Moser Date: Tue, 30 Aug 2016 14:06:14 +0200 Subject: [PATCH 029/492] Rename index.md to README.md to conform to our standards, every other file is named README.md --- data-mapper/{index.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data-mapper/{index.md => README.md} (100%) diff --git a/data-mapper/index.md b/data-mapper/README.md similarity index 100% rename from data-mapper/index.md rename to data-mapper/README.md From 9dd1503e6f02d6cf48e549aa97b8273cadd74274 Mon Sep 17 00:00:00 2001 From: NooBxGockeL Date: Tue, 30 Aug 2016 15:07:49 +0200 Subject: [PATCH 030/492] Work on #190: add postPumlsToServer.py python script Used to initially post all pumls to the plantuml hosting while preserving the pumlId's --- _scripts/postPumlsToServer.firstrun.output | 190 +++++++++++++++++++++ _scripts/postPumlsToServer.py | 44 +++++ 2 files changed, 234 insertions(+) create mode 100644 _scripts/postPumlsToServer.firstrun.output create mode 100644 _scripts/postPumlsToServer.py diff --git a/_scripts/postPumlsToServer.firstrun.output b/_scripts/postPumlsToServer.firstrun.output new file mode 100644 index 000000000..ea77a49a5 --- /dev/null +++ b/_scripts/postPumlsToServer.firstrun.output @@ -0,0 +1,190 @@ +parent: half-sync-half-async; artifact: half-sync-half-async +Puml Server ID: RScv3SCm3030LU819FRPXg5fIm552tnYPFiyjRi3RkbAaYkdoQr5JBy369vrxz7oaSv6XmPhL3e6TCaJ0msU-CAoilTToyG8DdKOw5z0GzcAlvNAN_WZSD1brBHHPmxv0000 +parent: abstract-document; artifact: abstract-document +Puml Server ID: PSjB3eCm34NHhPG599vtDyQn85L-ifzX-p3lxEf8Twj3MXGDQvyJMFubChxpKN767gucSq07iinEjSNDOACVNvoAUZr6MWoe3QVE_WRnxZ0Mf38b-hkIGlurX_MyehS7 +parent: tolerant-reader; artifact: tolerant-reader +Puml Server ID: NSZ14SCm20NHLf829ExfXaYChGn26lZ4xSVdtFRjSrZJx9AkZnFOyI9olkenSEOxGxmjWnXgMvE6viLWfmz_kNI9SLZP38XRqEIuWx1Kd0t5XVjjGVj_DNtMdLD_ +parent: event-driven-architecture; artifact: event-driven-architecture +Puml Server ID: TOhH3SCW30LNQGS0_tSRnrZ15H1adfFromBzkfFktZQaHT7mzgh0N1yYvoUVXXf7B7Mv1dGWozN9MZmCTlhopQdeidEaoO3wMDHvRI6zzvwAssPYbsfGGRYIGlxN7DxpZDv- +parent: publish-subscribe; artifact: publish-subscribe +Puml Server ID: PSZB3SCm203GLTe1RExT1XCKKs5YyMdMR--zFRsd66aTNAwFcRdZ1U1uzrDorgXWfykIBJjT2qJhnaI7Dtwm7HnoMjkOoMu12-C7s3LKOhQe4UGo63ZfVtlvwhkMVW40 +parent: facade; artifact: facade +Puml Server ID: BSP15eCm20N0gxG7CEoz3ILKqvTW7dpq-hhehERTJ7fMJU-l7PYn4ZbVPMlOyvEXBeT13KMEGQtdnM2d7v-yL8sssJ8PKBUWmV64lYnSbHJoRqaVPUReDm00 +parent: service-locator; artifact: service-locator +Puml Server ID: NSjB3iCm203HgxG7iDdtDeIWX0fZYqzo_MRTtUX9ynOZhPtBzNLchlW0EDxza3nhgs2dQScMdUO0qRenqU6B5xQTGmvh2pFPBM1WF07FSmbnqqcOqu6J_gsNZxvgw0y0 +parent: dao; artifact: dao +Puml Server ID: 5SR14OKW30N0LhG0oVrt4o6ZE12Ov4NR_thQNQlc5aN2sd82qtz4naywAixOmyNoK8WYvT6fjdWOR7JnpLiHhuTkam4nTUhiRwZm847-J64zpUZj3m00 +parent: model-view-presenter; artifact: model-view-presenter +Puml Server ID: ROlR3SGW3C1MkGu0-RzjKeXQJWcWFChwPO3xispvQBrmL0hbp-q-xGkWkFBL_8upZBICxjGzbo7GE1OwAlpmmLJ9sjNJH7VIRY1e6q169KvFevMcakrtI_BoD-HGoJE4Nm00 +parent: observer; artifact: observer +Puml Server ID: FSkn4OGm30NHLg00hFow4KO3PcpP8tr1-pYwx6smQz5Suv2mkbp0y1-HyPlEWYlsSB7S5Q98kJSgDLu66ztyy7Q8brEtmO2OEZNs2Uhxl9u9GVv72cjfHAiV +parent: intercepting-filter; artifact: intercepting-filter +Puml Server ID: RSfB3i8m303Hgy014k-vZN5DQkIuaJ_q-fGzkz7JtCL8Q-DolUsPAnu0ZcSVadizAzZfi6JBJiS4qJenqU6D7smRXmnh2pFPBM1YN05o_KwyKcoqb-ZFEEcVz_BPLqtz0W00 +parent: factory-method; artifact: factory-method +Puml Server ID: NSZB3G8n30N0Lg20n7UwCOxPP9MVx6TMT0zdRgEvjoazYeRrMmMsFuYChtmqr7Y6gycQq8aiQr3hSJ7OwEGtfwBUZfas0shJQR3_G2yMBFkaeQYha4B-AeUDl6FqBm00 +parent: private-class-data; artifact: private-class-data +Puml Server ID: RShR3SCm243HLTe1RFwx3S4eeSB4uf6itmpGlwkZ-nOZhS7b-ZeoLtm07E--InwrLR3JQScMdSu9edLZeiCNBso3GtPh2pFPBM1YF07BvSBaHeeHRJm_SD8VxkMphvhw0m00 +parent: async-method-invocation; artifact: async-method-invocation +Puml Server ID: TSdB3SCW303GLTe1mFTkunWhk0A3_4dKxTi5UdlIUuhIoCPfuz4Zjhy03EzwIlGyqjbeQR16fJL1HjuOQF362qjZbrFBnWWsTPZeFm3wHwbCZhvQ4RqMOSXIuA1_LzDctJd75m00 +parent: execute-around; artifact: execute-around +Puml Server ID: NSZ14G8n20NGLhI0XBlT865suoGa0n_NylNixSsxTvEHJTF7xGHsF8YShtfqdFdCK9TbK4ELDQcFl1ZizE8tbwRH3okR0NKBcXm_a7vK4bhOLreZXVnLJPzrvnnV +parent: monostate; artifact: monostate +Puml Server ID: HSV14OGm20NGLjO23FVj1YEZsGaa0nzjVxrvUszfLdlkaju_9p3ZI-HybwFXp2r3l0w364eTIgtdpM2d7r-yxXBji7Ko86v1ol60TDW8C8G4zLr9rp9J-ny0 +parent: thread-pool; artifact: thread-pool +Puml Server ID: JSV14SCW30J0Lk82GFzq8uF6a1624IUx_UIPt-xHhMXK2TTN0zP-4pa_-UfeSSOMBzCWXbpceAxnCDZfmpUdAhjVbXO3uhPfyFw1q5oufZMdag3yFuUFl6Be5m00 +parent: delegation; artifact: delegation +Puml Server ID: JSV14GCX20NGLf82LkxfXbN69OFeu2VRVdBCxRsdUhLiac6F2rZxHHHybwwuyimjKQT37ANEGMfvCpZepHy-ccpjVYm697pJuFq3DJ7f39rEWlhNaZ7Aoc5V +parent: chain; artifact: chain +Puml Server ID: 9SR13SCm20NGLTe1OkxTXX0KKzd4Wa-pVYlrdTxJN4OTMZ4U7LZv8Wg-ssdejLTgoELGHvDhaesw6HpqvWzlXwQTlYq6D3nfSlv2qjcS5F9VgvXjrHnV +parent: resource-acquisition-is-initialization; artifact: resource-acquisition-is-initialization +Puml Server ID: ZShR3S8m343HLUW0YV_PnhXMQvGumOzMOdhA1lqxkhgBABLSEQqzzeZfJm33isuIUxxIsMXei4QbqK5QdXXeyCO3oyekcvQ94MpgqD4lWB6FDEA2z4bn2HbQn8leHMponNy13hgvrhHUP_Rs0m00 +parent: fluentinterface; artifact: fluentinterface +Puml Server ID: NOj93eCm302_KXv0VEzlN6F0bMCYB_3zvjpRQ3IpY97MnkNwEZD7l04SdtP8dlMfOAVBaYqRNHr4wy54Xo_Uk6uSSjWwC9FT0Zh61DYrPY_pyXs9WPF-NIllRLJN7m00 +parent: service-layer; artifact: service-layer +Puml Server ID: LOl93SCm3C1MQGUmzUysgY8aAcJ5q96WszVV_aW2V8gHriRb-ZWoPxm07E--Inxrhc2dqv8jEvq3HEl6H8SFNjWs3jcjJSnaju21iG3MSmbnK_mkuwJ_qij7dpNq1m00 +parent: visitor; artifact: visitor +Puml Server ID: DSR14OGm20NGLhG0mtsxmSWeJa8oyD7sTo_xJczLgoqFIM_B1Spu43c_vLHSkMU8rs4GGwcZaxPy6UnqyyFR8Q6dRPC1SGlg7B_Gew4OJeBwVqdlPMPlNm00 +parent: double-dispatch; artifact: double-dispatch +Puml Server ID: NSbB3iCW303HgpG70Ezx6yTOWSeOv4zp_MRTtUZDCPGa6wV9gqTiVmCOtlKQqVDCPwEbmHgLreGXUMEWmGU_M1hxkBHiZ61JXud-1BILft1fmvz37JZetshQh3kd_000 +parent: monad; artifact: monad +Puml Server ID: 9SR13SCm20NGLPe1OkxTXjWeSMMm1Pza_LRgExsjMntP97syBc35cyZvAMV7bKU6U9q6CPGwbVh8Xy5E7xvvRnBzj7qn86v1ol4BwJHk9AZ_bNGjAtLy0G00 +parent: front-controller; artifact: front-controller +Puml Server ID: PSlB3OGm303HLfO24j-t6nCC13bEvC_IFk6yjz6JPgbIE3OAvS_fFkmBe7Zde_ePQnXfwU8adajlK3bkT5Iuy8Tf8wk7f87kf6BGq6R0hlD8xwQTUG9v-SCSslA8nWy0 +parent: strategy; artifact: strategy +Puml Server ID: FSV13OCm30NGLM00udktCS4AGOaJsTz5tRwSkBstLiqj3WbhombC_n0PtwbKdB67Y-MX44NAerDjSJFOwE8lRuTuBRfD1iJKgRC_88SnfFn8aD-ai9vczFO7 +parent: command; artifact: command +Puml Server ID: DSgn4OCm30NGLM00h3xR25i7vYpXaxx2-g59zugtTgiZcwIFvGHcV8YSdt9qdBbdYDVR88PIRwK-yc6mqyLVtff4FsoR38XRa7Aye3SgMoD1_RkaQvcfumS0 +parent: abstract-factory; artifact: abstract-factory +Puml Server ID: PSZB3OD034NHLa81Czwd6sCC39gVxEUWT1_ssLmTtQLqgR5fM7sTmFGtaV6TZu8prd0r6HtQaMKqAZLk1XjT_E6qgPUZfyc0MdTgx0-8LuUn8ErFXdr98NypXxKyezKV +parent: flux; artifact: flux +Puml Server ID: 7SP14eCm20NGg-W13FlU1YFLE0GpyAazVZk-rPkRLSrDqdKwW14l8kUxx0r7hXdYzJA8eTIhKzEy6UnqyeUNJQBjjWm6n2seS_n3Ryql2UgJajxBoAu_ +parent: event-aggregator; artifact: event-aggregator +Puml Server ID: PSf13iCW30NHgxG70Ezx6uTOX0eCih-JwvTzTwEdUJSjFKu9wwyBMFuXCdvoRRZY21ShKo6ANEQWrkDXiD6NRqwdUAkQ5WDYwZJOTv3SUqzSgqbbp0qeVvZ3Hbun-Wy0 +parent: singleton; artifact: singleton +Puml Server ID: HSV14SCm20J0Lk82BFxf1ikCh0n26ZZizfDVVhjRjwfvIhg-Bc35cyZvAQtZoYD3l4w364gTWxhcms2d3z-ydnAzsRuO4BUWmV43HRUcWcaagF-Lz55M3lq2 +parent: null-object; artifact: null-object +Puml Server ID: JSV14SCm20J0Lk829Fxf1cF6bWSX3JhYzfDdVhjRSx4yDCDU5p3NcoZugMV3bNik3HaETLGPdPhbm-2WcpzS3btjz38PqF15dTSFv6bMndwhW1Jo_vhHwynkNm00 +parent: multiton; artifact: multiton +Puml Server ID: FST14i8m20NGg-W16lRUXgPCYnD81Zxs-hfozzvJlOywf68yBc3bYoZuRgVYghrIea-7E5gVHZhgPd3Gcp-y7P9w-hOOaF0au_o1h0OKqqdG_saLrbRP-080 +parent: composite; artifact: composite +Puml Server ID: HSf13eCm30NHgy01YFUzZGaM62LEP7-NwvTTT_EaMTLgoqFIst81Cpv4payv5LVk6U9r6CHGwkYaBHy6EztyvUsGqDEsoO2u1NMED-WTvmY5aA3-LT9xcTdR3m00 +parent: api-gateway; artifact: image-microservice +Puml Server ID: 3Sp13SCm2030LTe1RFxTXX3aK1biOOZLxPlVlUujHZrFJk-lAsAk3u3ZhatYoYCNEmqBjgWq5AJdna27BzvOJbxIh4oCOBS5Yki1u9JIC7ZZ3pW8HB5nKI4VJtSBSKtNEbFx7m00 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'api-gateway/etc/image-microservice.urm.puml' +pumlid: 3Sp13SCm2030LTe1RFxTXX3aK1biOOZLxPlVlUujHZrFJk-lAsAk3u3ZhatYoYCNEmqBjgWq5AJdna27BzvOJbxIh4oCOBS5Yki1u9JIC7ZZ3pW8HB5nKI4VJtSBSKtNEbFx7m00 +parent: api-gateway; artifact: api-gateway-service +Puml Server ID: JSox3SCm303HLP819FRUXg49cO542_nOyFPncUvUSszHwhbpMdyT4TCt0CDLcyIHdtGsEZLOez8vG7ek33JuueLbPvUcPM84cpeCz2S0fvI6mGjluA1_b-Tt2N5D6tNcw3y0 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'api-gateway/etc/api-gateway-service.urm.puml' +pumlid: JSox3SCm303HLP819FRUXg49cO542_nOyFPncUvUSszHwhbpMdyT4TCt0CDLcyIHdtGsEZLOez8vG7ek33JuueLbPvUcPM84cpeCz2S0fvI6mGjluA1_b-Tt2N5D6tNcw3y0 +parent: api-gateway; artifact: price-microservice +Puml Server ID: 3Sn13iGW243HgqmFeEpdDfGIoqJK8DJqzkFklyq_f56DYyFgvtOVymjWk78Hl-ECoKQzEJVFr1Mana97Wny-c2wUKbeQwCxM9YZE7O13Ka7dXI-m4mmJugH2rlVksSXXcaTe_GC0 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'api-gateway/etc/price-microservice.urm.puml' +pumlid: 3Sn13iGW243HgqmFeEpdDfGIoqJK8DJqzkFklyq_f56DYyFgvtOVymjWk78Hl-ECoKQzEJVFr1Mana97Wny-c2wUKbeQwCxM9YZE7O13Ka7dXI-m4mmJugH2rlVksSXXcaTe_GC0 +parent: object-pool; artifact: object-pool +Puml Server ID: JSV94SCm2030Lk829Fxf1cF6bWU1XYDkFtdcjxiD9Qc3o-LrPQvu0pW-_HnvrLx1JgR9cfrimf1wCD7XnW-sWsESsXPcicl0nFW1RB-PiYqp0KxwVo-VVTMKBm00 +parent: adapter; artifact: adapter +Puml Server ID: DSR14S8m30J0Lg20M7-wEMnDOiPMFDA9j0yyUEtUkzMHJTF7xI1NF4GSLzaxZtncgDVJgCPIpobzv0N2vOKtjgRHTziMI7KBcOXl10thfxB-Nz9dMJd71m00 +parent: hexagonal; artifact: hexagonal +Puml Server ID: HSTB4W8X30N0g-W1XkozpPD90LO8L3wEnzUTk-xxq2fvSfhSUiJs1v7XAcr4psSwMrqQh57gcZGaBmICNdZZEDb7qsCZWasT9lm7wln1MmeXZlfVIPjbvvGl +parent: value-object; artifact: value-object +Puml Server ID: LSZ13SCm20NGLTe1RExTXX2KECBOmfza_VRQszDxDnVBNJFiTG9pVOY2dteqdBdbqf3XK4ULqQbPFWmEklZcikjgXvV9W8Olwhn-e9ijjOpjKW4fv2zgHgypktq1 +parent: twin; artifact: twin +Puml Server ID: 7SR13OCm30NGLUW0n7UsCS42eyH4zdUpFbNVwNtKQij3qjjo0ICs8kTPJiMLUuPuVGnYAFNff2qdWvrk_l9wIEXfws10t88wno-4gKQ2-az9xsLaRoy0 +parent: semaphore; artifact: semaphore +Puml Server ID: HSV14SCm20J0Lk82BFxf1ikCfOn06ZZizfDVVhjRjphobFJnQi2ADv7pKwwEbaU6U9q6CPGwbVh8Xy5E7xvvFoNwPVjYGDo2bEC72b5URRgGeFvNqhMirF45 +parent: message-channel; artifact: message-channel +Puml Server ID: NSZB3SCm203GLTe1RExTXX1akm9YyMdMRy-zFRtdCf8wkLmUCtF72y3nxcFbhAE2dIvBjknqAIof6nCTtlZ1TdAiOMrZ9hi5ACOFe1o1WnjDD6C1Jlg_NgvzbyeN +parent: poison-pill; artifact: poison-pill +Puml Server ID: JSZ14SCm20NHLf82BExfXiYCJGOX3NpYzkDZRllsgTwjTgcmnmciV145N-rGdFMkbEZJ8OxMvo2rkXWSzE4lRxka7huj1YGyQN3UGMjgpdkh6Gdwlrl5QAk6_G00 +parent: aggregator-microservices; artifact: aggregator-service +Puml Server ID: JOov3SCm301NIGQGs7iRXYPa1g8ayB7NjuiKwGvtmBrbKC-Tq_hhY5Y-0HXUjKaS-Kbdepc2HrIQ2jBpma23BvvOTdPfeooCO1iEYlu0O6l63MDQKI6Rp-CKOWSE-ey_NzEqhjH-0m00 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'aggregator-microservices/etc/aggregator-service.urm.puml' +pumlid: JOov3SCm301NIGQGs7iRXYPa1g8ayB7NjuiKwGvtmBrbKC-Tq_hhY5Y-0HXUjKaS-Kbdepc2HrIQ2jBpma23BvvOTdPfeooCO1iEYlu0O6l63MDQKI6Rp-CKOWSE-ey_NzEqhjH-0m00 +parent: aggregator-microservices; artifact: information-microservice +Puml Server ID: LSnB3i8m303Hgy016k-vZN5DQXGxaJ_jzUcMtKXFcgSOZTgvV3oEp1Kl0CUhTScZtXNiD2tPij5Ka54N9ZfyySHjvv1ksy9CTWjGZ3i0UtVkcDCt5V9vFquX3k0a4FjCLqoPzgUjNDig7Jy0 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'aggregator-microservices/etc/information-microservice.urm.puml' +pumlid: LSnB3i8m303Hgy016k-vZN5DQXGxaJ_jzUcMtKXFcgSOZTgvV3oEp1Kl0CUhTScZtXNiD2tPij5Ka54N9ZfyySHjvv1ksy9CTWjGZ3i0UtVkcDCt5V9vFquX3k0a4FjCLqoPzgUjNDig7Jy0 +parent: aggregator-microservices; artifact: inventory-microservice +Puml Server ID: LSpB3G8n303HLg20ZUzqOxnMrYXn8d-oedjovJRIIEyfIYrFJckFAsBw2y3mBbNYodSw6mqDrYWqEaZB6mCDFhZmEDcbwZ4nWaqTEleEm5gDAyQmemlPsCOIOWSE0j6riM7VlrVIUfdPsmy0 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'aggregator-microservices/etc/inventory-microservice.urm.puml' +pumlid: LSpB3G8n303HLg20ZUzqOxnMrYXn8d-oedjovJRIIEyfIYrFJckFAsBw2y3mBbNYodSw6mqDrYWqEaZB6mCDFhZmEDcbwZ4nWaqTEleEm5gDAyQmemlPsCOIOWSE0j6riM7VlrVIUfdPsmy0 +parent: bridge; artifact: bridge +Puml Server ID: BSR14SCm20J0Lf82BFxf1akCJ4R26ZZYzkE7zxLljJgoIVfu7S2A3v7pLRhYo3r3l9u6CPHwJjAH5uETllpZhKbejsqn86v1a-CExQwj2mdgqv8-oyev_W00 +parent: servant; artifact: servant +Puml Server ID: DSkn4O0m20NGLNG0G-ys63cDbv0SV7HzRUnUy-QYkSOkONKwWU4haV6JZe8pjd2nt1MYIBatAZKU1XjTVFEoYvT3by60c3erzW_qdPiL9CY_KrXB8rfz0G00 +parent: lazy-loading; artifact: lazy-loading +Puml Server ID: LSXB3W8X303Gg-W1e7jlqu66gIc5zED4JwzRTo_lpjeaEwN9xOpO_W0mlEhWEFD89sjBWpHgMnDOyi90WoU-i7Ho7besHf2fmqJ_0GG_xo8BE-i0YlONDMtMdLE- +parent: flyweight; artifact: flyweight +Puml Server ID: HSV94S8m3030Lg20M7-w4OvYAoCh7Xtnq3ty-Eq-MQlaJcdow17JNm26gpIEdkzqidffa4Qfrm2MN1XeSEADsqxEJRU94MJgCD1_W4C-YxZr08hwNqaRPUQGBm00 +parent: mutex; artifact: mutex +Puml Server ID: 9SR13OCm30NGLSe0n7UsCS62LB69x6zWV2hrdTxKhFRS9Br_3c34GkHybxtXo3L3l9u6CPHwAhMUDuETldpnl4cqtUR1WBW5ASSlf0bvI53_A-bQHcf_0G00 +parent: mediator; artifact: mediator +Puml Server ID: FSV14SCm20J0Lk82BFxf1akCJKOW3JhizfDNVhkRUktP9AE_Bc2kDr7mKqx5bKSkYJeSuYXr66dFXy517xvvRxBqz7qo8E6BZDSFPDAKCO84zP-IOMMczIy0 +parent: page-object; artifact: page-object +Puml Server ID: JSV14OGW30NGLjO28FVj9iOCua1Wme-sxnxtzjvMJLeS6ju-9p3NbyZvoQNYZ3sMkWo36hACJhN5ms2dYszEXwvQB4q6r6rHv_K3JIwQndwfW1Jo_npUyupUNW00 +parent: factory-kit; artifact: factory-kit +Puml Server ID: JST15i8m20N0g-W14lRU1YcsQ4BooCS-RwzBTpDNSscvQKQx7C1SDwBWi-w68--vD6Gur55bTBAM9uE3dlpcikcotSjaGCCNTLu_q8C58pxbPI25_Bzcz3gpjoy0 +parent: property; artifact: property +Puml Server ID: FSV13OCm30NGLTe1YEziumOBKYMEPN-3s9wUUdlltRJst2Izlmx0OYLolihUSEGdGxnEXIXAdODQpul1Jby-UTaasgwBCI2kGOFZ1pAV9ewR1FMVaZwAvUWF +parent: dependency-injection; artifact: dependency-injection +Puml Server ID: RSdB3SCW303GLPe1mFTkunWhSGG6-PEesxS3zFQajubIpyPf_NL6B7y363xra3XpJsUZgS4QbUO0wVbWeC65DvR6BeUMXH5iwZ3GVu36YxMnqgU8NamXKu63_aPD6tNbw5y0 +parent: layers; artifact: layers +Puml Server ID: BSR13OCm30NGLSe0n7UsCS62L8w9x6yGszD3t-bDpQhc9kdwEO0H2v7pNVQ68zSCyNeQn53gsQbftWns-lB5yoRHTfi70-8Mr3b-8UL7F4XG_otflOpi-W80 +parent: producer-consumer; artifact: producer-consumer +Puml Server ID: PSjB3iCW303HgxG70Ezx6zTO2HKso9_a-c7VtUX9y-vA8nkdZTSPiVm3O7ZNeyUPttGscXgiKMaAz94t1XhyyCBIsFkXPM44cpe8-WvODbiIMzcdfspXe7-jQL9NodW0 +parent: builder; artifact: builder +Puml Server ID: DSR94O0m2030LhG0mzzkC64KXs26GzlNZw_TcRLADagJwOWOlW8OFcNdE79B9wkN1ccKUdLWoGS33KwySMdalEioC89C7Jhw5zYIfNrIrFybhPUHNLu0 +parent: specification; artifact: specification +Puml Server ID: LSX14i8m20NGg-W16lRU1YcsE0d9mCTUNxVkthoxkVJQjQBVJc3bWoZuQeVXh6UbXao7EfhCGTRhOd3Gcp-yxPfs-BOOqF2amVa3vLAnbmd3ffD2_gTLZBPgz2y0 +parent: state; artifact: state +Puml Server ID: 9SRH3O0m20N0LNG0ox_RO2LQqz867hg-9jxNpKLpZLt2wdG2mrSYuoST1MTiuMAvAqIHSczKQZmCDhhuvcKNBuSkWm4nTMhiNyZ141BaVocifH6jlW00 +parent: reader-writer-lock; artifact: reader-writer-lock +Puml Server ID: RSZB4S8m303HLg00MtUw4R8cCP5bZpwuVL80jttxx4gIZTFaSKOiVm4OxdhqEFETpaPJWpKgpG5TScEWmGU_M1fxFxGiZ61JXu5-1nXZOolR-gqYaoxWe3-xfeswSiWF +parent: interpreter; artifact: interpreter +Puml Server ID: JSf13eCm30NHgz034E-vZGaM62Kcih_BzQ6xxjv8yr6hBJT9RzC1Z5Y8dE-oAuvSCyJhPH13gLSdRNapsEdaBy-RXEus3mR4BQXpl21zVnykFmlgVvVqNaRszW00 +parent: template-method; artifact: template-method +Puml Server ID: NSZ13SCW30NGLPe1mFTkuu0Lg6n0vZjPlpttzlIEFef6bN1zDM3jDv7paw-E5cTiyJ87P22NQTGr7WOxVVZcL6NtQwJ5WFZOPBn_88WjPKWoGPkL1EN_ShZb5QPV +parent: feature-toggle; artifact: feature-toggle +Puml Server ID: NSZ14G8X30NGLhG0oDrk8XjPd12OvCTjNy_UthpxiAPvIBhUJc37WyZvgdtWp6U6U5i6CTIs9WtDYy5ER_vmEIH6jx8P4BUWoV43lOIHBWMhTnKIjB-gwRFkdFe5 +parent: business-delegate; artifact: business-delegate +Puml Server ID: POl13SCm3CHMQGU8zUysgYCuBcJ5a4x9-l6_Fu84tzsgvYxf-Zg06HyYvxkqZYE_6UBrD8YXr7DGrxmPxFJZYxTTeZVR9WFY5ZGu5j2wkad4wYgD8IIe_xQaZp9pw0C0 +parent: naked-objects; artifact: naked-objects-integtests +Puml Server ID: LSmn4iCW30NHgoG70FMvZGmQ6ni48tt5ru_RT3kls7VJqgDAM7yTmF8FaV6TzuOZjd2nCXMYo6KEQZrk1XkT_ELKnTkkQJ4Wfaw3_GbIlgIckPrIu2Ge_vBQyziX3izX8wyO_GS0 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'naked-objects/etc/naked-objects-integtests.urm.puml' +pumlid: LSmn4iCW30NHgoG70FMvZGmQ6ni48tt5ru_RT3kls7VJqgDAM7yTmF8FaV6TzuOZjd2nCXMYo6KEQZrk1XkT_ELKnTkkQJ4Wfaw3_GbIlgIckPrIu2Ge_vBQyziX3izX8wyO_GS0 +parent: naked-objects; artifact: naked-objects-dom +Puml Server ID: LSZ94SCW3030Lf82G7zt8mkDZOC4eyDkF_dcjxFlhZIoSTfudH7BDm33fnuzpjpJsMXgi4QbAT17FXXeSE6DfR7tGyl223Pr4FGVGF73hSpzOWe73lgVqgRKDAahPNm1 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'naked-objects/etc/naked-objects-dom.urm.puml' +pumlid: LSZ94SCW3030Lf82G7zt8mkDZOC4eyDkF_dcjxFlhZIoSTfudH7BDm33fnuzpjpJsMXgi4QbAT17FXXeSE6DfR7tGyl223Pr4FGVGF73hSpzOWe73lgVqgRKDAahPNm1 +parent: naked-objects; artifact: naked-objects-fixture +Puml Server ID: LSX15i8W30N0g-W187jlaq9igH1uoO_r-BfrDs_kJKkFAc7zTW3B7qJ6LzuRZjZ2nSfKY2ANEQZrk1XiTFARKnLlkwR5W9Ww3VOVIFabDStjb08dGVcVz6mVX4aE6td5w5y0 +I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'naked-objects/etc/naked-objects-fixture.urm.puml' +pumlid: LSX15i8W30N0g-W187jlaq9igH1uoO_r-BfrDs_kJKkFAc7zTW3B7qJ6LzuRZjZ2nSfKY2ANEQZrk1XiTFARKnLlkwR5W9Ww3VOVIFabDStjb08dGVcVz6mVX4aE6td5w5y0 +parent: model-view-controller; artifact: model-view-controller +Puml Server ID: ROl13SCm201NQGUm-NSRQgE42h258Lw_wR-_qvtkoTOaEwNBuuoOwmNWkEl1SUOx5taR5cHHsr1WoOs13X-yi7HQV5YP645k2nJN3Q2ZavIBQPVVwqFajXJjVwdfMcUgV040 +parent: proxy; artifact: proxy +Puml Server ID: 9SR13OCm30NGLM00udktCS62eCI9x6yesrEfx_Jcehd69c5rEe3X7oBZE-q5HwpXOhahH95oRrHgt0msEldYPHClkow30J5rQko_qB3-VKYG_qjXBOrezGK0 +parent: memento; artifact: memento +Puml Server ID: DSgn4OCm30NGLM00h3xR2AC3SvRiaxx2-g59zugtDgiz3qdlomNC-10vF-Lik7BF4A_388PIXrBh-J3OwUOlRuT4EssR38XRa7Ay81Lz_o11_RkaQvcf_GS0 +parent: decorator; artifact: decorator +Puml Server ID: HSV14SCm20J0Lk82BFxf1YF6LaP26ZZizfDVVhjRC-bPDRs_Bc35cyZvAMV3bKU6kao36ehCGQtdms2d3z-yLursshuOKBUWmV43LPNfZEcaaFzA-YWhH_y2 +parent: data-mapper; artifact: data-mapper +Puml Server ID: JShB3OGm303HLg20nFVjnYGM1CN6ycTfVtFSsnjfzY5jPgUqkLqHwXy0mxUU8wuyqidQ8q4IjJqCO-QBWGOtVh5qyd5AKOmW4mT6Nu2-ZiAekapH_hkcSTNa-GC0 +parent: caching; artifact: caching +Puml Server ID: DSRB4OKm2030LhG0m_rrWyWaE0bc-6ZxpujxsbMKUXwSrfSMCVq7OFYKAj5oJsUZIuCr2bq3fEU3WGOdthWTx59rcnZ1fWu3_GqGKXEjm47VIzeeCqV_0m00 +parent: reactor; artifact: reactor +Puml Server ID: DSR14OGm20NGLjO23FVj1f7Hx2Ga0nzjVxtuJc-f9YrtJM-V4vZn9NA-or5nvfQXBiEWXYAZKsrvCzZfnnUlkqOzR9qCg5jGvtX2hYmOJWfvNz9xcTdR7m00 +parent: iterator; artifact: iterator +Puml Server ID: FSV13OGm30NHLg00uljsOu85HeaJsTzB-yjfBwCtgrfjUKXwMovWneV8-IcduiezGxmEWnXA7PsqvSDWfvk_l1qIUjes6H2teCxnWlGDOpW9wdzAUYypU_i1 +parent: callback; artifact: callback +Puml Server ID: FSVB4S8m30N0Lg20M7UwUL4qYOciUFGXxSE9s-wp6sjjKgwF8tF6YyXnjxtdKMk5E5-MOjdu6jIrRYIStlXWsIJwRij4fhW53SGFn51TmIT9yZ-jVBHPGxy0 +parent: repository; artifact: repository +Puml Server ID: JSV13OCm30NGLM00udktCS42eyI9xE-YRjyUUtjlLQij3qblomNCU14vF-LKNBbdYDTX44EfevEsV1ZiTFERjqD2Jzic0-8Mr3b-89SvGZ7yGuBwrvBUoypUlW00 +parent: mute-idiom; artifact: mute-idiom +Puml Server ID: JSf13iCm20NHgxG7iDdtDjH62PKX5luarq-MtSsJvgtUHdR96AyTcEj357pLJR7dDvT4EnpYgEqmqf4NWuD-V7BfidJpCXcGy4N6wmcoX1Jj-lo2ziUQONMcZHi0 +parent: prototype; artifact: prototype +Puml Server ID: HSV13OCm30NGLM00udktCS62eCInxE-YRj_UUdjlRLfx7fBUbmkmU14vF-Lik7BF4AzJ8OfIvw3Mys6mqyrltWw9Tkfc38XhqE3uWSmd9Zuc9AZ_bVHHB4V_0W00 +parent: step-builder; artifact: step-builder +Puml Server ID: LOZ93SCm3C1MQGQmzUysYYqaAcJ5q96i7t_x8KXkh4soKvfypeZfNm33fnuSP-xfPEtI88tQhW4i-M2WmGzlB9sS3oqJ8yZKOQ0lWOLPzcJfAoZQtwXfeyuSyW80 +parent: double-checked-locking; artifact: double-checked-locking +Puml Server ID: TSdH4SCW203GLTe1bFzkGv1J6qGFeLc_MI1_x-wzkv94uJ1vDVUrFm26LwxTMnonsMYgitgcEQ1BNEXeyCKVfiAxLqqBtTbqmy1z0ygCGpXHOpgv99bqTgt0JW-LmqPUCUGF diff --git a/_scripts/postPumlsToServer.py b/_scripts/postPumlsToServer.py new file mode 100644 index 000000000..2f975d3d8 --- /dev/null +++ b/_scripts/postPumlsToServer.py @@ -0,0 +1,44 @@ +import requests, glob, re, os + +# taken from here: http://stackoverflow.com/a/13641746 +def replace(file, pattern, subst): + # Read contents from file as a single string + file_handle = open(file, 'r') + file_string = file_handle.read() + file_handle.close() + + # Use RE package to allow for replacement (also allowing for (multiline) REGEX) + file_string = (re.sub(pattern, subst, file_string)) + + # Write contents to file. + # Using mode 'w' truncates the file. + file_handle = open(file, 'w') + file_handle.write(file_string) + file_handle.close() + +# list of all puml files +fileList = glob.glob('*/etc/*.puml') +for puml in fileList: + pathSplit = puml.split("/") + # parent folder + parent = pathSplit[0] + # individual artifact/project name + artifact = pathSplit[2].replace(".urm.puml", "") + print "parent: " + parent + "; artifact: " + artifact + + # do a POST to the official plantuml hosting site with a little trick "!includeurl" and raw github content + data = { + 'text': "!includeurl https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/" + puml + } + r = requests.post('http://plantuml.com/plantuml/uml', data=data) + pumlId = r.url.replace("http://plantuml.com/plantuml/uml/", "") + + # the only thing needed to get a png/svg/ascii from the server back + print "Puml Server ID: " + pumlId + + # add the id so jekyll/liquid can use it + if (parent == artifact): + replace("./" + parent + "/README.md", "categories:", "pumlid: {}\\ncategories:".format(pumlId)) + else: + print "I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file '" + puml + "'\npumlid: {}".format(pumlId) + From 58dce1bd89a5b448b238ec3e0fe8adc77b15c41f Mon Sep 17 00:00:00 2001 From: NooBxGockeL Date: Tue, 30 Aug 2016 15:10:34 +0200 Subject: [PATCH 031/492] Work on #190: Commit initial pumlId's added by the script --- abstract-document/README.md | 1 + abstract-factory/README.md | 1 + adapter/README.md | 1 + aggregator-microservices/README.md | 1 + api-gateway/README.md | 1 + async-method-invocation/README.md | 1 + bridge/README.md | 1 + builder/README.md | 1 + business-delegate/README.md | 1 + caching/README.md | 1 + callback/README.md | 1 + chain/README.md | 1 + command/README.md | 1 + composite/README.md | 1 + dao/README.md | 1 + data-mapper/README.md | 1 + decorator/README.md | 1 + delegation/README.md | 1 + dependency-injection/README.md | 1 + double-checked-locking/README.md | 1 + double-dispatch/README.md | 1 + event-aggregator/README.md | 1 + event-driven-architecture/README.md | 1 + execute-around/README.md | 1 + facade/README.md | 1 + factory-kit/README.md | 1 + factory-method/README.md | 1 + feature-toggle/README.md | 1 + fluentinterface/README.md | 1 + flux/README.md | 1 + flyweight/README.md | 1 + front-controller/README.md | 1 + half-sync-half-async/README.md | 1 + hexagonal/README.md | 1 + intercepting-filter/README.md | 1 + interpreter/README.md | 1 + iterator/README.md | 1 + layers/README.md | 1 + lazy-loading/README.md | 1 + mediator/README.md | 1 + memento/README.md | 1 + message-channel/README.md | 1 + model-view-controller/README.md | 1 + model-view-presenter/README.md | 1 + monad/README.md | 1 + monostate/README.md | 1 + multiton/README.md | 1 + mute-idiom/README.md | 1 + mutex/README.md | 1 + naked-objects/README.md | 1 + null-object/README.md | 1 + object-pool/README.md | 1 + observer/README.md | 1 + page-object/README.md | 1 + poison-pill/README.md | 1 + private-class-data/README.md | 1 + producer-consumer/README.md | 1 + property/README.md | 1 + prototype/README.md | 1 + proxy/README.md | 1 + publish-subscribe/README.md | 1 + reactor/README.md | 1 + reader-writer-lock/README.md | 1 + repository/README.md | 1 + resource-acquisition-is-initialization/README.md | 1 + semaphore/README.md | 1 + servant/README.md | 1 + service-layer/README.md | 1 + service-locator/README.md | 1 + singleton/README.md | 1 + specification/README.md | 1 + state/README.md | 1 + step-builder/README.md | 1 + strategy/README.md | 1 + template-method/README.md | 1 + thread-pool/README.md | 1 + tolerant-reader/README.md | 1 + twin/README.md | 1 + value-object/README.md | 1 + visitor/README.md | 1 + 80 files changed, 80 insertions(+) diff --git a/abstract-document/README.md b/abstract-document/README.md index bf28ff999..c8755ce07 100644 --- a/abstract-document/README.md +++ b/abstract-document/README.md @@ -3,6 +3,7 @@ layout: pattern title: Abstract Document folder: abstract-document permalink: /patterns/abstract-document/ +pumlid: PSjB3eCm34NHhPG599vtDyQn85L-ifzX-p3lxEf8Twj3MXGDQvyJMFubChxpKN767gucSq07iinEjSNDOACVNvoAUZr6MWoe3QVE_WRnxZ0Mf38b-hkIGlurX_MyehS7 categories: Structural tags: - Java diff --git a/abstract-factory/README.md b/abstract-factory/README.md index 485599b98..2a8fecd36 100644 --- a/abstract-factory/README.md +++ b/abstract-factory/README.md @@ -3,6 +3,7 @@ layout: pattern title: Abstract Factory folder: abstract-factory permalink: /patterns/abstract-factory/ +pumlid: PSZB3OD034NHLa81Czwd6sCC39gVxEUWT1_ssLmTtQLqgR5fM7sTmFGtaV6TZu8prd0r6HtQaMKqAZLk1XjT_E6qgPUZfyc0MdTgx0-8LuUn8ErFXdr98NypXxKyezKV categories: Creational tags: - Java diff --git a/adapter/README.md b/adapter/README.md index ea3baa7fa..66ca63826 100644 --- a/adapter/README.md +++ b/adapter/README.md @@ -3,6 +3,7 @@ layout: pattern title: Adapter folder: adapter permalink: /patterns/adapter/ +pumlid: DSR14S8m30J0Lg20M7-wEMnDOiPMFDA9j0yyUEtUkzMHJTF7xI1NF4GSLzaxZtncgDVJgCPIpobzv0N2vOKtjgRHTziMI7KBcOXl10thfxB-Nz9dMJd71m00 categories: Structural tags: - Java diff --git a/aggregator-microservices/README.md b/aggregator-microservices/README.md index e65f26d9a..75fe373fd 100644 --- a/aggregator-microservices/README.md +++ b/aggregator-microservices/README.md @@ -3,6 +3,7 @@ layout: pattern title: Aggregator Microservices folder: aggregator-microservices permalink: /patterns/aggregator-microservices/ +pumlid: JOov3SCm301NIGQGs7iRXYPa1g8ayB7NjuiKwGvtmBrbKC-Tq_hhY5Y-0HXUjKaS-Kbdepc2HrIQ2jBpma23BvvOTdPfeooCO1iEYlu0O6l63MDQKI6Rp-CKOWSE-ey_NzEqhjH-0m00 categories: Architectural tags: - Java diff --git a/api-gateway/README.md b/api-gateway/README.md index 23014ae0b..93b975e13 100644 --- a/api-gateway/README.md +++ b/api-gateway/README.md @@ -3,6 +3,7 @@ layout: pattern title: API Gateway folder: api-gateway permalink: /patterns/api-gateway/ +pumlid: JSox3SCm303HLP819FRUXg49cO542_nOyFPncUvUSszHwhbpMdyT4TCt0CDLcyIHdtGsEZLOez8vG7ek33JuueLbPvUcPM84cpeCz2S0fvI6mGjluA1_b-Tt2N5D6tNcw3y0 categories: Architectural tags: - Java diff --git a/async-method-invocation/README.md b/async-method-invocation/README.md index 2d99820c5..b96c1d77a 100644 --- a/async-method-invocation/README.md +++ b/async-method-invocation/README.md @@ -3,6 +3,7 @@ layout: pattern title: Async Method Invocation folder: async-method-invocation permalink: /patterns/async-method-invocation/ +pumlid: TSdB3SCW303GLTe1mFTkunWhk0A3_4dKxTi5UdlIUuhIoCPfuz4Zjhy03EzwIlGyqjbeQR16fJL1HjuOQF362qjZbrFBnWWsTPZeFm3wHwbCZhvQ4RqMOSXIuA1_LzDctJd75m00 categories: Concurrency tags: - Java diff --git a/bridge/README.md b/bridge/README.md index 49dad14e4..6c1e70631 100644 --- a/bridge/README.md +++ b/bridge/README.md @@ -3,6 +3,7 @@ layout: pattern title: Bridge folder: bridge permalink: /patterns/bridge/ +pumlid: BSR14SCm20J0Lf82BFxf1akCJ4R26ZZYzkE7zxLljJgoIVfu7S2A3v7pLRhYo3r3l9u6CPHwJjAH5uETllpZhKbejsqn86v1a-CExQwj2mdgqv8-oyev_W00 categories: Structural tags: - Java diff --git a/builder/README.md b/builder/README.md index 5d1f3d24d..6a661502f 100644 --- a/builder/README.md +++ b/builder/README.md @@ -3,6 +3,7 @@ layout: pattern title: Builder folder: builder permalink: /patterns/builder/ +pumlid: DSR94O0m2030LhG0mzzkC64KXs26GzlNZw_TcRLADagJwOWOlW8OFcNdE79B9wkN1ccKUdLWoGS33KwySMdalEioC89C7Jhw5zYIfNrIrFybhPUHNLu0 categories: Creational tags: - Java diff --git a/business-delegate/README.md b/business-delegate/README.md index e6e249122..8e6e3456c 100644 --- a/business-delegate/README.md +++ b/business-delegate/README.md @@ -3,6 +3,7 @@ layout: pattern title: Business Delegate folder: business-delegate permalink: /patterns/business-delegate/ +pumlid: POl13SCm3CHMQGU8zUysgYCuBcJ5a4x9-l6_Fu84tzsgvYxf-Zg06HyYvxkqZYE_6UBrD8YXr7DGrxmPxFJZYxTTeZVR9WFY5ZGu5j2wkad4wYgD8IIe_xQaZp9pw0C0 categories: Business Tier tags: - Java diff --git a/caching/README.md b/caching/README.md index 2b89d0559..6432ffcea 100644 --- a/caching/README.md +++ b/caching/README.md @@ -3,6 +3,7 @@ layout: pattern title: Caching folder: caching permalink: /patterns/caching/ +pumlid: DSRB4OKm2030LhG0m_rrWyWaE0bc-6ZxpujxsbMKUXwSrfSMCVq7OFYKAj5oJsUZIuCr2bq3fEU3WGOdthWTx59rcnZ1fWu3_GqGKXEjm47VIzeeCqV_0m00 categories: Other tags: - Java diff --git a/callback/README.md b/callback/README.md index a408fd5e0..278aa9b0a 100644 --- a/callback/README.md +++ b/callback/README.md @@ -3,6 +3,7 @@ layout: pattern title: Callback folder: callback permalink: /patterns/callback/ +pumlid: FSVB4S8m30N0Lg20M7UwUL4qYOciUFGXxSE9s-wp6sjjKgwF8tF6YyXnjxtdKMk5E5-MOjdu6jIrRYIStlXWsIJwRij4fhW53SGFn51TmIT9yZ-jVBHPGxy0 categories: Other tags: - Java diff --git a/chain/README.md b/chain/README.md index ef18f6f64..5ab4b2256 100644 --- a/chain/README.md +++ b/chain/README.md @@ -3,6 +3,7 @@ layout: pattern title: Chain of responsibility folder: chain permalink: /patterns/chain/ +pumlid: 9SR13SCm20NGLTe1OkxTXX0KKzd4Wa-pVYlrdTxJN4OTMZ4U7LZv8Wg-ssdejLTgoELGHvDhaesw6HpqvWzlXwQTlYq6D3nfSlv2qjcS5F9VgvXjrHnV categories: Behavioral tags: - Java diff --git a/command/README.md b/command/README.md index a5478394c..9fb568f62 100644 --- a/command/README.md +++ b/command/README.md @@ -3,6 +3,7 @@ layout: pattern title: Command folder: command permalink: /patterns/command/ +pumlid: DSgn4OCm30NGLM00h3xR25i7vYpXaxx2-g59zugtTgiZcwIFvGHcV8YSdt9qdBbdYDVR88PIRwK-yc6mqyLVtff4FsoR38XRa7Aye3SgMoD1_RkaQvcfumS0 categories: Behavioral tags: - Java diff --git a/composite/README.md b/composite/README.md index 8b980292d..fce6ed6af 100644 --- a/composite/README.md +++ b/composite/README.md @@ -3,6 +3,7 @@ layout: pattern title: Composite folder: composite permalink: /patterns/composite/ +pumlid: HSf13eCm30NHgy01YFUzZGaM62LEP7-NwvTTT_EaMTLgoqFIst81Cpv4payv5LVk6U9r6CHGwkYaBHy6EztyvUsGqDEsoO2u1NMED-WTvmY5aA3-LT9xcTdR3m00 categories: Structural tags: - Java diff --git a/dao/README.md b/dao/README.md index 785a1c362..b1b655edf 100644 --- a/dao/README.md +++ b/dao/README.md @@ -3,6 +3,7 @@ layout: pattern title: Data Access Object folder: dao permalink: /patterns/dao/ +pumlid: 5SR14OKW30N0LhG0oVrt4o6ZE12Ov4NR_thQNQlc5aN2sd82qtz4naywAixOmyNoK8WYvT6fjdWOR7JnpLiHhuTkam4nTUhiRwZm847-J64zpUZj3m00 categories: Persistence Tier tags: - Java diff --git a/data-mapper/README.md b/data-mapper/README.md index 075e8eece..362f19c51 100644 --- a/data-mapper/README.md +++ b/data-mapper/README.md @@ -3,6 +3,7 @@ layout: pattern title: Data Mapper folder: data-mapper permalink: /patterns/data-mapper/ +pumlid: JShB3OGm303HLg20nFVjnYGM1CN6ycTfVtFSsnjfzY5jPgUqkLqHwXy0mxUU8wuyqidQ8q4IjJqCO-QBWGOtVh5qyd5AKOmW4mT6Nu2-ZiAekapH_hkcSTNa-GC0 categories: Persistence Tier tags: - Java diff --git a/decorator/README.md b/decorator/README.md index 63795114c..e65b0eb9e 100644 --- a/decorator/README.md +++ b/decorator/README.md @@ -3,6 +3,7 @@ layout: pattern title: Decorator folder: decorator permalink: /patterns/decorator/ +pumlid: HSV14SCm20J0Lk82BFxf1YF6LaP26ZZizfDVVhjRC-bPDRs_Bc35cyZvAMV3bKU6kao36ehCGQtdms2d3z-yLursshuOKBUWmV43LPNfZEcaaFzA-YWhH_y2 categories: Structural tags: - Java diff --git a/delegation/README.md b/delegation/README.md index e5c0c6376..b294607ec 100644 --- a/delegation/README.md +++ b/delegation/README.md @@ -3,6 +3,7 @@ layout: pattern title: Delegation folder: delegation permalink: /patterns/delegation/ +pumlid: JSV14GCX20NGLf82LkxfXbN69OFeu2VRVdBCxRsdUhLiac6F2rZxHHHybwwuyimjKQT37ANEGMfvCpZepHy-ccpjVYm697pJuFq3DJ7f39rEWlhNaZ7Aoc5V categories: Behavioral tags: - Java diff --git a/dependency-injection/README.md b/dependency-injection/README.md index 735f589b1..b4ec12e6b 100644 --- a/dependency-injection/README.md +++ b/dependency-injection/README.md @@ -3,6 +3,7 @@ layout: pattern title: Dependency Injection folder: dependency-injection permalink: /patterns/dependency-injection/ +pumlid: RSdB3SCW303GLPe1mFTkunWhSGG6-PEesxS3zFQajubIpyPf_NL6B7y363xra3XpJsUZgS4QbUO0wVbWeC65DvR6BeUMXH5iwZ3GVu36YxMnqgU8NamXKu63_aPD6tNbw5y0 categories: Behavioral tags: - Java diff --git a/double-checked-locking/README.md b/double-checked-locking/README.md index da1fdd1a2..582e4aac6 100644 --- a/double-checked-locking/README.md +++ b/double-checked-locking/README.md @@ -3,6 +3,7 @@ layout: pattern title: Double Checked Locking folder: double-checked-locking permalink: /patterns/double-checked-locking/ +pumlid: TSdH4SCW203GLTe1bFzkGv1J6qGFeLc_MI1_x-wzkv94uJ1vDVUrFm26LwxTMnonsMYgitgcEQ1BNEXeyCKVfiAxLqqBtTbqmy1z0ygCGpXHOpgv99bqTgt0JW-LmqPUCUGF categories: Concurrency tags: - Java diff --git a/double-dispatch/README.md b/double-dispatch/README.md index ae87208a2..b0f2185f9 100644 --- a/double-dispatch/README.md +++ b/double-dispatch/README.md @@ -3,6 +3,7 @@ layout: pattern title: Double Dispatch folder: double-dispatch permalink: /patterns/double-dispatch/ +pumlid: NSbB3iCW303HgpG70Ezx6yTOWSeOv4zp_MRTtUZDCPGa6wV9gqTiVmCOtlKQqVDCPwEbmHgLreGXUMEWmGU_M1hxkBHiZ61JXud-1BILft1fmvz37JZetshQh3kd_000 categories: Other tags: - Java diff --git a/event-aggregator/README.md b/event-aggregator/README.md index ac07869e7..ce7f358de 100644 --- a/event-aggregator/README.md +++ b/event-aggregator/README.md @@ -3,6 +3,7 @@ layout: pattern title: Event Aggregator folder: event-aggregator permalink: /patterns/event-aggregator/ +pumlid: PSf13iCW30NHgxG70Ezx6uTOX0eCih-JwvTzTwEdUJSjFKu9wwyBMFuXCdvoRRZY21ShKo6ANEQWrkDXiD6NRqwdUAkQ5WDYwZJOTv3SUqzSgqbbp0qeVvZ3Hbun-Wy0 categories: Structural tags: - Java diff --git a/event-driven-architecture/README.md b/event-driven-architecture/README.md index 843e4c268..0f698273b 100644 --- a/event-driven-architecture/README.md +++ b/event-driven-architecture/README.md @@ -3,6 +3,7 @@ layout: pattern title: Event Driven Architecture folder: event-driven-architecture permalink: /patterns/event-driven-architecture/ +pumlid: TOhH3SCW30LNQGS0_tSRnrZ15H1adfFromBzkfFktZQaHT7mzgh0N1yYvoUVXXf7B7Mv1dGWozN9MZmCTlhopQdeidEaoO3wMDHvRI6zzvwAssPYbsfGGRYIGlxN7DxpZDv- categories: Architectural tags: - Java diff --git a/execute-around/README.md b/execute-around/README.md index f669f18ff..e0ae128b5 100644 --- a/execute-around/README.md +++ b/execute-around/README.md @@ -3,6 +3,7 @@ layout: pattern title: Execute Around folder: execute-around permalink: /patterns/execute-around/ +pumlid: NSZ14G8n20NGLhI0XBlT865suoGa0n_NylNixSsxTvEHJTF7xGHsF8YShtfqdFdCK9TbK4ELDQcFl1ZizE8tbwRH3okR0NKBcXm_a7vK4bhOLreZXVnLJPzrvnnV categories: Other tags: - Java diff --git a/facade/README.md b/facade/README.md index c416552c7..22ccd6911 100644 --- a/facade/README.md +++ b/facade/README.md @@ -3,6 +3,7 @@ layout: pattern title: Facade folder: facade permalink: /patterns/facade/ +pumlid: BSP15eCm20N0gxG7CEoz3ILKqvTW7dpq-hhehERTJ7fMJU-l7PYn4ZbVPMlOyvEXBeT13KMEGQtdnM2d7v-yL8sssJ8PKBUWmV64lYnSbHJoRqaVPUReDm00 categories: Structural tags: - Java diff --git a/factory-kit/README.md b/factory-kit/README.md index c25701047..b47cbff76 100644 --- a/factory-kit/README.md +++ b/factory-kit/README.md @@ -3,6 +3,7 @@ layout: pattern title: Factory Kit folder: factory-kit permalink: /patterns/factory-kit/ +pumlid: JST15i8m20N0g-W14lRU1YcsQ4BooCS-RwzBTpDNSscvQKQx7C1SDwBWi-w68--vD6Gur55bTBAM9uE3dlpcikcotSjaGCCNTLu_q8C58pxbPI25_Bzcz3gpjoy0 categories: Creational tags: - Java diff --git a/factory-method/README.md b/factory-method/README.md index 05549cf4f..a444ffbd8 100644 --- a/factory-method/README.md +++ b/factory-method/README.md @@ -3,6 +3,7 @@ layout: pattern title: Factory Method folder: factory-method permalink: /patterns/factory-method/ +pumlid: NSZB3G8n30N0Lg20n7UwCOxPP9MVx6TMT0zdRgEvjoazYeRrMmMsFuYChtmqr7Y6gycQq8aiQr3hSJ7OwEGtfwBUZfas0shJQR3_G2yMBFkaeQYha4B-AeUDl6FqBm00 categories: Creational tags: - Java diff --git a/feature-toggle/README.md b/feature-toggle/README.md index 51747ac09..3bb91ad5a 100644 --- a/feature-toggle/README.md +++ b/feature-toggle/README.md @@ -3,6 +3,7 @@ layout: pattern title: Feature Toggle folder: feature-toggle permalink: /patterns/feature-toggle/ +pumlid: NSZ14G8X30NGLhG0oDrk8XjPd12OvCTjNy_UthpxiAPvIBhUJc37WyZvgdtWp6U6U5i6CTIs9WtDYy5ER_vmEIH6jx8P4BUWoV43lOIHBWMhTnKIjB-gwRFkdFe5 categories: Behavioral tags: - Java diff --git a/fluentinterface/README.md b/fluentinterface/README.md index 767792da7..8bf43d974 100644 --- a/fluentinterface/README.md +++ b/fluentinterface/README.md @@ -3,6 +3,7 @@ layout: pattern title: Fluent Interface folder: fluentinterface permalink: /patterns/fluentinterface/ +pumlid: NOj93eCm302_KXv0VEzlN6F0bMCYB_3zvjpRQ3IpY97MnkNwEZD7l04SdtP8dlMfOAVBaYqRNHr4wy54Xo_Uk6uSSjWwC9FT0Zh61DYrPY_pyXs9WPF-NIllRLJN7m00 categories: Other tags: - Java diff --git a/flux/README.md b/flux/README.md index 7ac312c44..e36b73900 100644 --- a/flux/README.md +++ b/flux/README.md @@ -3,6 +3,7 @@ layout: pattern title: Flux folder: flux permalink: /patterns/flux/ +pumlid: 7SP14eCm20NGg-W13FlU1YFLE0GpyAazVZk-rPkRLSrDqdKwW14l8kUxx0r7hXdYzJA8eTIhKzEy6UnqyeUNJQBjjWm6n2seS_n3Ryql2UgJajxBoAu_ categories: Presentation Tier tags: - Java diff --git a/flyweight/README.md b/flyweight/README.md index a98dced8e..1e71f1c02 100644 --- a/flyweight/README.md +++ b/flyweight/README.md @@ -3,6 +3,7 @@ layout: pattern title: Flyweight folder: flyweight permalink: /patterns/flyweight/ +pumlid: HSV94S8m3030Lg20M7-w4OvYAoCh7Xtnq3ty-Eq-MQlaJcdow17JNm26gpIEdkzqidffa4Qfrm2MN1XeSEADsqxEJRU94MJgCD1_W4C-YxZr08hwNqaRPUQGBm00 categories: Structural tags: - Java diff --git a/front-controller/README.md b/front-controller/README.md index a462a08e0..c832674dc 100644 --- a/front-controller/README.md +++ b/front-controller/README.md @@ -3,6 +3,7 @@ layout: pattern title: Front Controller folder: front-controller permalink: /patterns/front-controller/ +pumlid: PSlB3OGm303HLfO24j-t6nCC13bEvC_IFk6yjz6JPgbIE3OAvS_fFkmBe7Zde_ePQnXfwU8adajlK3bkT5Iuy8Tf8wk7f87kf6BGq6R0hlD8xwQTUG9v-SCSslA8nWy0 categories: Presentation Tier tags: - Java diff --git a/half-sync-half-async/README.md b/half-sync-half-async/README.md index 8a091f813..55891e770 100644 --- a/half-sync-half-async/README.md +++ b/half-sync-half-async/README.md @@ -3,6 +3,7 @@ layout: pattern title: Half-Sync/Half-Async folder: half-sync-half-async permalink: /patterns/half-sync-half-async/ +pumlid: RScv3SCm3030LU819FRPXg5fIm552tnYPFiyjRi3RkbAaYkdoQr5JBy369vrxz7oaSv6XmPhL3e6TCaJ0msU-CAoilTToyG8DdKOw5z0GzcAlvNAN_WZSD1brBHHPmxv0000 categories: Concurrency tags: - Java diff --git a/hexagonal/README.md b/hexagonal/README.md index b1d0a7948..33c2ba9cb 100644 --- a/hexagonal/README.md +++ b/hexagonal/README.md @@ -3,6 +3,7 @@ layout: pattern title: Hexagonal Architecture folder: hexagonal permalink: /patterns/hexagonal/ +pumlid: HSTB4W8X30N0g-W1XkozpPD90LO8L3wEnzUTk-xxq2fvSfhSUiJs1v7XAcr4psSwMrqQh57gcZGaBmICNdZZEDb7qsCZWasT9lm7wln1MmeXZlfVIPjbvvGl categories: Architectural tags: - Java diff --git a/intercepting-filter/README.md b/intercepting-filter/README.md index 7d53472a0..4981299ad 100644 --- a/intercepting-filter/README.md +++ b/intercepting-filter/README.md @@ -3,6 +3,7 @@ layout: pattern title: Intercepting Filter folder: intercepting-filter permalink: /patterns/intercepting-filter/ +pumlid: RSfB3i8m303Hgy014k-vZN5DQkIuaJ_q-fGzkz7JtCL8Q-DolUsPAnu0ZcSVadizAzZfi6JBJiS4qJenqU6D7smRXmnh2pFPBM1YN05o_KwyKcoqb-ZFEEcVz_BPLqtz0W00 categories: Behavioral tags: - Java diff --git a/interpreter/README.md b/interpreter/README.md index 87c1c47f7..7a09ab0c7 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -3,6 +3,7 @@ layout: pattern title: Interpreter folder: interpreter permalink: /patterns/interpreter/ +pumlid: JSf13eCm30NHgz034E-vZGaM62Kcih_BzQ6xxjv8yr6hBJT9RzC1Z5Y8dE-oAuvSCyJhPH13gLSdRNapsEdaBy-RXEus3mR4BQXpl21zVnykFmlgVvVqNaRszW00 categories: Behavioral tags: - Java diff --git a/iterator/README.md b/iterator/README.md index d6be7758d..91cc64d8d 100644 --- a/iterator/README.md +++ b/iterator/README.md @@ -3,6 +3,7 @@ layout: pattern title: Iterator folder: iterator permalink: /patterns/iterator/ +pumlid: FSV13OGm30NHLg00uljsOu85HeaJsTzB-yjfBwCtgrfjUKXwMovWneV8-IcduiezGxmEWnXA7PsqvSDWfvk_l1qIUjes6H2teCxnWlGDOpW9wdzAUYypU_i1 categories: Behavioral tags: - Java diff --git a/layers/README.md b/layers/README.md index 8e8eda366..d62c6b6b7 100644 --- a/layers/README.md +++ b/layers/README.md @@ -3,6 +3,7 @@ layout: pattern title: Layers folder: layers permalink: /patterns/layers/ +pumlid: BSR13OCm30NGLSe0n7UsCS62L8w9x6yGszD3t-bDpQhc9kdwEO0H2v7pNVQ68zSCyNeQn53gsQbftWns-lB5yoRHTfi70-8Mr3b-8UL7F4XG_otflOpi-W80 categories: Architectural tags: - Java diff --git a/lazy-loading/README.md b/lazy-loading/README.md index d40061293..4b7a580c3 100644 --- a/lazy-loading/README.md +++ b/lazy-loading/README.md @@ -3,6 +3,7 @@ layout: pattern title: Lazy Loading folder: lazy-loading permalink: /patterns/lazy-loading/ +pumlid: LSXB3W8X303Gg-W1e7jlqu66gIc5zED4JwzRTo_lpjeaEwN9xOpO_W0mlEhWEFD89sjBWpHgMnDOyi90WoU-i7Ho7besHf2fmqJ_0GG_xo8BE-i0YlONDMtMdLE- categories: Other tags: - Java diff --git a/mediator/README.md b/mediator/README.md index c7a0478c8..0e9f9c216 100644 --- a/mediator/README.md +++ b/mediator/README.md @@ -3,6 +3,7 @@ layout: pattern title: Mediator folder: mediator permalink: /patterns/mediator/ +pumlid: FSV14SCm20J0Lk82BFxf1akCJKOW3JhizfDNVhkRUktP9AE_Bc2kDr7mKqx5bKSkYJeSuYXr66dFXy517xvvRxBqz7qo8E6BZDSFPDAKCO84zP-IOMMczIy0 categories: Behavioral tags: - Java diff --git a/memento/README.md b/memento/README.md index 463b5fec0..f43849329 100644 --- a/memento/README.md +++ b/memento/README.md @@ -3,6 +3,7 @@ layout: pattern title: Memento folder: memento permalink: /patterns/memento/ +pumlid: DSgn4OCm30NGLM00h3xR2AC3SvRiaxx2-g59zugtDgiz3qdlomNC-10vF-Lik7BF4A_388PIXrBh-J3OwUOlRuT4EssR38XRa7Ay81Lz_o11_RkaQvcf_GS0 categories: Behavioral tags: - Java diff --git a/message-channel/README.md b/message-channel/README.md index 8aebd0157..aa357ac0c 100644 --- a/message-channel/README.md +++ b/message-channel/README.md @@ -3,6 +3,7 @@ layout: pattern title: Message Channel folder: message-channel permalink: /patterns/message-channel/ +pumlid: NSZB3SCm203GLTe1RExTXX1akm9YyMdMRy-zFRtdCf8wkLmUCtF72y3nxcFbhAE2dIvBjknqAIof6nCTtlZ1TdAiOMrZ9hi5ACOFe1o1WnjDD6C1Jlg_NgvzbyeN categories: Integration tags: - Java diff --git a/model-view-controller/README.md b/model-view-controller/README.md index bc96f7ab1..9907b98bd 100644 --- a/model-view-controller/README.md +++ b/model-view-controller/README.md @@ -3,6 +3,7 @@ layout: pattern title: Model-View-Controller folder: model-view-controller permalink: /patterns/model-view-controller/ +pumlid: ROl13SCm201NQGUm-NSRQgE42h258Lw_wR-_qvtkoTOaEwNBuuoOwmNWkEl1SUOx5taR5cHHsr1WoOs13X-yi7HQV5YP645k2nJN3Q2ZavIBQPVVwqFajXJjVwdfMcUgV040 categories: Presentation Tier tags: - Java diff --git a/model-view-presenter/README.md b/model-view-presenter/README.md index a3b921ce4..04a1fa559 100644 --- a/model-view-presenter/README.md +++ b/model-view-presenter/README.md @@ -3,6 +3,7 @@ layout: pattern title: Model-View-Presenter folder: model-view-presenter permalink: /patterns/model-view-presenter/ +pumlid: ROlR3SGW3C1MkGu0-RzjKeXQJWcWFChwPO3xispvQBrmL0hbp-q-xGkWkFBL_8upZBICxjGzbo7GE1OwAlpmmLJ9sjNJH7VIRY1e6q169KvFevMcakrtI_BoD-HGoJE4Nm00 categories: Presentation Tier tags: - Java diff --git a/monad/README.md b/monad/README.md index 41edd3d92..bf6ee58b8 100644 --- a/monad/README.md +++ b/monad/README.md @@ -3,6 +3,7 @@ layout: pattern title: Monad folder: monad permalink: /patterns/monad/ +pumlid: 9SR13SCm20NGLPe1OkxTXjWeSMMm1Pza_LRgExsjMntP97syBc35cyZvAMV7bKU6U9q6CPGwbVh8Xy5E7xvvRnBzj7qn86v1ol4BwJHk9AZ_bNGjAtLy0G00 categories: Other tags: - Java diff --git a/monostate/README.md b/monostate/README.md index 3576dc659..8c47b5da4 100644 --- a/monostate/README.md +++ b/monostate/README.md @@ -3,6 +3,7 @@ layout: pattern title: MonoState folder: monostate permalink: /patterns/monostate/ +pumlid: HSV14OGm20NGLjO23FVj1YEZsGaa0nzjVxrvUszfLdlkaju_9p3ZI-HybwFXp2r3l0w364eTIgtdpM2d7r-yxXBji7Ko86v1ol60TDW8C8G4zLr9rp9J-ny0 categories: Creational tags: - Java diff --git a/multiton/README.md b/multiton/README.md index 0462ff0ec..a1154e7bb 100644 --- a/multiton/README.md +++ b/multiton/README.md @@ -3,6 +3,7 @@ layout: pattern title: Multiton folder: multiton permalink: /patterns/multiton/ +pumlid: FST14i8m20NGg-W16lRUXgPCYnD81Zxs-hfozzvJlOywf68yBc3bYoZuRgVYghrIea-7E5gVHZhgPd3Gcp-y7P9w-hOOaF0au_o1h0OKqqdG_saLrbRP-080 categories: Creational tags: - Java diff --git a/mute-idiom/README.md b/mute-idiom/README.md index bb674b648..5c3dbf10b 100644 --- a/mute-idiom/README.md +++ b/mute-idiom/README.md @@ -3,6 +3,7 @@ layout: pattern title: Mute Idiom folder: mute-idiom permalink: /patterns/mute-idiom/ +pumlid: JSf13iCm20NHgxG7iDdtDjH62PKX5luarq-MtSsJvgtUHdR96AyTcEj357pLJR7dDvT4EnpYgEqmqf4NWuD-V7BfidJpCXcGy4N6wmcoX1Jj-lo2ziUQONMcZHi0 categories: Other tags: - Java diff --git a/mutex/README.md b/mutex/README.md index 84755872f..78cda9060 100644 --- a/mutex/README.md +++ b/mutex/README.md @@ -3,6 +3,7 @@ layout: pattern title: Mutex folder: mutex permalink: /patterns/mutex/ +pumlid: 9SR13OCm30NGLSe0n7UsCS62LB69x6zWV2hrdTxKhFRS9Br_3c34GkHybxtXo3L3l9u6CPHwAhMUDuETldpnl4cqtUR1WBW5ASSlf0bvI53_A-bQHcf_0G00 categories: Concurrency tags: - Java diff --git a/naked-objects/README.md b/naked-objects/README.md index 66e6ac2b0..14391dd40 100644 --- a/naked-objects/README.md +++ b/naked-objects/README.md @@ -3,6 +3,7 @@ layout: pattern title: Naked Objects folder: naked-objects permalink: /patterns/naked-objects/ +pumlid: LSX15i8W30N0g-W187jlaq9igH1uoO_r-BfrDs_kJKkFAc7zTW3B7qJ6LzuRZjZ2nSfKY2ANEQZrk1XiTFARKnLlkwR5W9Ww3VOVIFabDStjb08dGVcVz6mVX4aE6td5w5y0 categories: Architectural tags: - Java diff --git a/null-object/README.md b/null-object/README.md index 0ed28a0af..bfaaeac66 100644 --- a/null-object/README.md +++ b/null-object/README.md @@ -3,6 +3,7 @@ layout: pattern title: Null Object folder: null-object permalink: /patterns/null-object/ +pumlid: JSV14SCm20J0Lk829Fxf1cF6bWSX3JhYzfDdVhjRSx4yDCDU5p3NcoZugMV3bNik3HaETLGPdPhbm-2WcpzS3btjz38PqF15dTSFv6bMndwhW1Jo_vhHwynkNm00 categories: Behavioral tags: - Java diff --git a/object-pool/README.md b/object-pool/README.md index cf36d9880..15fee51aa 100644 --- a/object-pool/README.md +++ b/object-pool/README.md @@ -3,6 +3,7 @@ layout: pattern title: Object Pool folder: object-pool permalink: /patterns/object-pool/ +pumlid: JSV94SCm2030Lk829Fxf1cF6bWU1XYDkFtdcjxiD9Qc3o-LrPQvu0pW-_HnvrLx1JgR9cfrimf1wCD7XnW-sWsESsXPcicl0nFW1RB-PiYqp0KxwVo-VVTMKBm00 categories: Creational tags: - Java diff --git a/observer/README.md b/observer/README.md index 6fbe3cdab..6a9e3f584 100644 --- a/observer/README.md +++ b/observer/README.md @@ -3,6 +3,7 @@ layout: pattern title: Observer folder: observer permalink: /patterns/observer/ +pumlid: FSkn4OGm30NHLg00hFow4KO3PcpP8tr1-pYwx6smQz5Suv2mkbp0y1-HyPlEWYlsSB7S5Q98kJSgDLu66ztyy7Q8brEtmO2OEZNs2Uhxl9u9GVv72cjfHAiV categories: Behavioral tags: - Java diff --git a/page-object/README.md b/page-object/README.md index b4f8246f1..2219a077c 100644 --- a/page-object/README.md +++ b/page-object/README.md @@ -3,6 +3,7 @@ layout: pattern title: Page Object folder: page-object permalink: /patterns/page-object/ +pumlid: JSV14OGW30NGLjO28FVj9iOCua1Wme-sxnxtzjvMJLeS6ju-9p3NbyZvoQNYZ3sMkWo36hACJhN5ms2dYszEXwvQB4q6r6rHv_K3JIwQndwfW1Jo_npUyupUNW00 categories: Testing tags: - Java diff --git a/poison-pill/README.md b/poison-pill/README.md index 0815b376e..8f673ad49 100644 --- a/poison-pill/README.md +++ b/poison-pill/README.md @@ -3,6 +3,7 @@ layout: pattern title: Poison Pill folder: poison-pill permalink: /patterns/poison-pill/ +pumlid: JSZ14SCm20NHLf82BExfXiYCJGOX3NpYzkDZRllsgTwjTgcmnmciV145N-rGdFMkbEZJ8OxMvo2rkXWSzE4lRxka7huj1YGyQN3UGMjgpdkh6Gdwlrl5QAk6_G00 categories: Other tags: - Java diff --git a/private-class-data/README.md b/private-class-data/README.md index 981208fa3..061cc9e77 100644 --- a/private-class-data/README.md +++ b/private-class-data/README.md @@ -3,6 +3,7 @@ layout: pattern title: Private Class Data folder: private-class-data permalink: /patterns/private-class-data/ +pumlid: RShR3SCm243HLTe1RFwx3S4eeSB4uf6itmpGlwkZ-nOZhS7b-ZeoLtm07E--InwrLR3JQScMdSu9edLZeiCNBso3GtPh2pFPBM1YF07BvSBaHeeHRJm_SD8VxkMphvhw0m00 categories: Other tags: - Java diff --git a/producer-consumer/README.md b/producer-consumer/README.md index 1bb84c35f..b3cb56af1 100644 --- a/producer-consumer/README.md +++ b/producer-consumer/README.md @@ -3,6 +3,7 @@ layout: pattern title: Producer Consumer folder: producer-consumer permalink: /patterns/producer-consumer/ +pumlid: PSjB3iCW303HgxG70Ezx6zTO2HKso9_a-c7VtUX9y-vA8nkdZTSPiVm3O7ZNeyUPttGscXgiKMaAz94t1XhyyCBIsFkXPM44cpe8-WvODbiIMzcdfspXe7-jQL9NodW0 categories: Concurrency tags: - Java diff --git a/property/README.md b/property/README.md index 0ac5c7a6c..c1502f75c 100644 --- a/property/README.md +++ b/property/README.md @@ -3,6 +3,7 @@ layout: pattern title: Property folder: property permalink: /patterns/property/ +pumlid: FSV13OCm30NGLTe1YEziumOBKYMEPN-3s9wUUdlltRJst2Izlmx0OYLolihUSEGdGxnEXIXAdODQpul1Jby-UTaasgwBCI2kGOFZ1pAV9ewR1FMVaZwAvUWF categories: Creational tags: - Java diff --git a/prototype/README.md b/prototype/README.md index 632daca93..fe9e17917 100644 --- a/prototype/README.md +++ b/prototype/README.md @@ -3,6 +3,7 @@ layout: pattern title: Prototype folder: prototype permalink: /patterns/prototype/ +pumlid: HSV13OCm30NGLM00udktCS62eCInxE-YRj_UUdjlRLfx7fBUbmkmU14vF-Lik7BF4AzJ8OfIvw3Mys6mqyrltWw9Tkfc38XhqE3uWSmd9Zuc9AZ_bVHHB4V_0W00 categories: Creational tags: - Java diff --git a/proxy/README.md b/proxy/README.md index a3e03708e..1c22c0710 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -3,6 +3,7 @@ layout: pattern title: Proxy folder: proxy permalink: /patterns/proxy/ +pumlid: 9SR13OCm30NGLM00udktCS62eCI9x6yesrEfx_Jcehd69c5rEe3X7oBZE-q5HwpXOhahH95oRrHgt0msEldYPHClkow30J5rQko_qB3-VKYG_qjXBOrezGK0 categories: Structural tags: - Java diff --git a/publish-subscribe/README.md b/publish-subscribe/README.md index 6a5b2dfa8..3265e42ea 100644 --- a/publish-subscribe/README.md +++ b/publish-subscribe/README.md @@ -3,6 +3,7 @@ layout: pattern title: Publish Subscribe folder: publish-subscribe permalink: /patterns/publish-subscribe/ +pumlid: PSZB3SCm203GLTe1RExT1XCKKs5YyMdMR--zFRsd66aTNAwFcRdZ1U1uzrDorgXWfykIBJjT2qJhnaI7Dtwm7HnoMjkOoMu12-C7s3LKOhQe4UGo63ZfVtlvwhkMVW40 categories: Integration tags: - Java diff --git a/reactor/README.md b/reactor/README.md index b9ba98948..7fd3982ad 100644 --- a/reactor/README.md +++ b/reactor/README.md @@ -3,6 +3,7 @@ layout: pattern title: Reactor folder: reactor permalink: /patterns/reactor/ +pumlid: DSR14OGm20NGLjO23FVj1f7Hx2Ga0nzjVxtuJc-f9YrtJM-V4vZn9NA-or5nvfQXBiEWXYAZKsrvCzZfnnUlkqOzR9qCg5jGvtX2hYmOJWfvNz9xcTdR7m00 categories: Concurrency tags: - Java diff --git a/reader-writer-lock/README.md b/reader-writer-lock/README.md index 40b711361..556b9cd85 100644 --- a/reader-writer-lock/README.md +++ b/reader-writer-lock/README.md @@ -3,6 +3,7 @@ layout: pattern title: Reader Writer Lock folder: reader-writer-lock permalink: /patterns/reader-writer-lock/ +pumlid: RSZB4S8m303HLg00MtUw4R8cCP5bZpwuVL80jttxx4gIZTFaSKOiVm4OxdhqEFETpaPJWpKgpG5TScEWmGU_M1fxFxGiZ61JXu5-1nXZOolR-gqYaoxWe3-xfeswSiWF categories: Concurrency tags: - Java diff --git a/repository/README.md b/repository/README.md index 67b3ea44e..501f39f9c 100644 --- a/repository/README.md +++ b/repository/README.md @@ -3,6 +3,7 @@ layout: pattern title: Repository folder: repository permalink: /patterns/repository/ +pumlid: JSV13OCm30NGLM00udktCS42eyI9xE-YRjyUUtjlLQij3qblomNCU14vF-LKNBbdYDTX44EfevEsV1ZiTFERjqD2Jzic0-8Mr3b-89SvGZ7yGuBwrvBUoypUlW00 categories: Persistence Tier tags: - Java diff --git a/resource-acquisition-is-initialization/README.md b/resource-acquisition-is-initialization/README.md index 821f220d7..df7ee294b 100644 --- a/resource-acquisition-is-initialization/README.md +++ b/resource-acquisition-is-initialization/README.md @@ -3,6 +3,7 @@ layout: pattern title: Resource Acquisition Is Initialization folder: resource-acquisition-is-initialization permalink: /patterns/resource-acquisition-is-initialization/ +pumlid: ZShR3S8m343HLUW0YV_PnhXMQvGumOzMOdhA1lqxkhgBABLSEQqzzeZfJm33isuIUxxIsMXei4QbqK5QdXXeyCO3oyekcvQ94MpgqD4lWB6FDEA2z4bn2HbQn8leHMponNy13hgvrhHUP_Rs0m00 categories: Other tags: - Java diff --git a/semaphore/README.md b/semaphore/README.md index 46ccd7b8e..071e061a7 100644 --- a/semaphore/README.md +++ b/semaphore/README.md @@ -3,6 +3,7 @@ layout: pattern title: Semaphore folder: semaphore permalink: /patterns/semaphore/ +pumlid: HSV14SCm20J0Lk82BFxf1ikCfOn06ZZizfDVVhjRjphobFJnQi2ADv7pKwwEbaU6U9q6CPGwbVh8Xy5E7xvvFoNwPVjYGDo2bEC72b5URRgGeFvNqhMirF45 categories: Concurrency tags: - Java diff --git a/servant/README.md b/servant/README.md index 3e82ab2cf..d14d35edf 100644 --- a/servant/README.md +++ b/servant/README.md @@ -3,6 +3,7 @@ layout: pattern title: Servant folder: servant permalink: /patterns/servant/ +pumlid: DSkn4O0m20NGLNG0G-ys63cDbv0SV7HzRUnUy-QYkSOkONKwWU4haV6JZe8pjd2nt1MYIBatAZKU1XjTVFEoYvT3by60c3erzW_qdPiL9CY_KrXB8rfz0G00 categories: Structural tags: - Java diff --git a/service-layer/README.md b/service-layer/README.md index 9b685d4e3..af393947f 100644 --- a/service-layer/README.md +++ b/service-layer/README.md @@ -3,6 +3,7 @@ layout: pattern title: Service Layer folder: service-layer permalink: /patterns/service-layer/ +pumlid: LOl93SCm3C1MQGUmzUysgY8aAcJ5q96WszVV_aW2V8gHriRb-ZWoPxm07E--Inxrhc2dqv8jEvq3HEl6H8SFNjWs3jcjJSnaju21iG3MSmbnK_mkuwJ_qij7dpNq1m00 categories: Architectural tags: - Java diff --git a/service-locator/README.md b/service-locator/README.md index af4d8c3ac..31d82b13f 100644 --- a/service-locator/README.md +++ b/service-locator/README.md @@ -3,6 +3,7 @@ layout: pattern title: Service Locator folder: service-locator permalink: /patterns/service-locator/ +pumlid: NSjB3iCm203HgxG7iDdtDeIWX0fZYqzo_MRTtUX9ynOZhPtBzNLchlW0EDxza3nhgs2dQScMdUO0qRenqU6B5xQTGmvh2pFPBM1WF07FSmbnqqcOqu6J_gsNZxvgw0y0 categories: Structural tags: - Java diff --git a/singleton/README.md b/singleton/README.md index 2a481f5c8..cd6fc131d 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -3,6 +3,7 @@ layout: pattern title: Singleton folder: singleton permalink: /patterns/singleton/ +pumlid: HSV14SCm20J0Lk82BFxf1ikCh0n26ZZizfDVVhjRjwfvIhg-Bc35cyZvAQtZoYD3l4w364gTWxhcms2d3z-ydnAzsRuO4BUWmV43HRUcWcaagF-Lz55M3lq2 categories: Creational tags: - Java diff --git a/specification/README.md b/specification/README.md index 564830653..dc47f4970 100644 --- a/specification/README.md +++ b/specification/README.md @@ -3,6 +3,7 @@ layout: pattern title: Specification folder: specification permalink: /patterns/specification/ +pumlid: LSX14i8m20NGg-W16lRU1YcsE0d9mCTUNxVkthoxkVJQjQBVJc3bWoZuQeVXh6UbXao7EfhCGTRhOd3Gcp-yxPfs-BOOqF2amVa3vLAnbmd3ffD2_gTLZBPgz2y0 categories: Behavioral tags: - Java diff --git a/state/README.md b/state/README.md index f5cb189fd..8e3256b42 100644 --- a/state/README.md +++ b/state/README.md @@ -3,6 +3,7 @@ layout: pattern title: State folder: state permalink: /patterns/state/ +pumlid: 9SRH3O0m20N0LNG0ox_RO2LQqz867hg-9jxNpKLpZLt2wdG2mrSYuoST1MTiuMAvAqIHSczKQZmCDhhuvcKNBuSkWm4nTMhiNyZ141BaVocifH6jlW00 categories: Behavioral tags: - Java diff --git a/step-builder/README.md b/step-builder/README.md index bc636e37a..65d356c2e 100644 --- a/step-builder/README.md +++ b/step-builder/README.md @@ -3,6 +3,7 @@ layout: pattern title: Step Builder folder: step-builder permalink: /patterns/step-builder/ +pumlid: LOZ93SCm3C1MQGQmzUysYYqaAcJ5q96i7t_x8KXkh4soKvfypeZfNm33fnuSP-xfPEtI88tQhW4i-M2WmGzlB9sS3oqJ8yZKOQ0lWOLPzcJfAoZQtwXfeyuSyW80 categories: Creational tags: - Java diff --git a/strategy/README.md b/strategy/README.md index f07397f67..697b6cc88 100644 --- a/strategy/README.md +++ b/strategy/README.md @@ -3,6 +3,7 @@ layout: pattern title: Strategy folder: strategy permalink: /patterns/strategy/ +pumlid: FSV13OCm30NGLM00udktCS4AGOaJsTz5tRwSkBstLiqj3WbhombC_n0PtwbKdB67Y-MX44NAerDjSJFOwE8lRuTuBRfD1iJKgRC_88SnfFn8aD-ai9vczFO7 categories: Behavioral tags: - Java diff --git a/template-method/README.md b/template-method/README.md index ad972f06b..65381d0ce 100644 --- a/template-method/README.md +++ b/template-method/README.md @@ -3,6 +3,7 @@ layout: pattern title: Template method folder: template-method permalink: /patterns/template-method/ +pumlid: NSZ13SCW30NGLPe1mFTkuu0Lg6n0vZjPlpttzlIEFef6bN1zDM3jDv7paw-E5cTiyJ87P22NQTGr7WOxVVZcL6NtQwJ5WFZOPBn_88WjPKWoGPkL1EN_ShZb5QPV categories: Behavioral tags: - Java diff --git a/thread-pool/README.md b/thread-pool/README.md index 9806fa8e0..473494ef9 100644 --- a/thread-pool/README.md +++ b/thread-pool/README.md @@ -3,6 +3,7 @@ layout: pattern title: Thread Pool folder: thread-pool permalink: /patterns/thread-pool/ +pumlid: JSV14SCW30J0Lk82GFzq8uF6a1624IUx_UIPt-xHhMXK2TTN0zP-4pa_-UfeSSOMBzCWXbpceAxnCDZfmpUdAhjVbXO3uhPfyFw1q5oufZMdag3yFuUFl6Be5m00 categories: Concurrency tags: - Java diff --git a/tolerant-reader/README.md b/tolerant-reader/README.md index be0085f2c..5d1cf80fd 100644 --- a/tolerant-reader/README.md +++ b/tolerant-reader/README.md @@ -3,6 +3,7 @@ layout: pattern title: Tolerant Reader folder: tolerant-reader permalink: /patterns/tolerant-reader/ +pumlid: NSZ14SCm20NHLf829ExfXaYChGn26lZ4xSVdtFRjSrZJx9AkZnFOyI9olkenSEOxGxmjWnXgMvE6viLWfmz_kNI9SLZP38XRqEIuWx1Kd0t5XVjjGVj_DNtMdLD_ categories: Integration tags: - Java diff --git a/twin/README.md b/twin/README.md index 3795236bb..092032a55 100644 --- a/twin/README.md +++ b/twin/README.md @@ -3,6 +3,7 @@ layout: pattern title: Twin folder: twin permalink: /patterns/twin/ +pumlid: 7SR13OCm30NGLUW0n7UsCS42eyH4zdUpFbNVwNtKQij3qjjo0ICs8kTPJiMLUuPuVGnYAFNff2qdWvrk_l9wIEXfws10t88wno-4gKQ2-az9xsLaRoy0 categories: Creational tags: - Java diff --git a/value-object/README.md b/value-object/README.md index 83223d8a2..a8e707b05 100644 --- a/value-object/README.md +++ b/value-object/README.md @@ -3,6 +3,7 @@ layout: pattern title: Value Object folder: value-object permalink: /patterns/value-object/ +pumlid: LSZ13SCm20NGLTe1RExTXX2KECBOmfza_VRQszDxDnVBNJFiTG9pVOY2dteqdBdbqf3XK4ULqQbPFWmEklZcikjgXvV9W8Olwhn-e9ijjOpjKW4fv2zgHgypktq1 categories: Creational tags: - Java diff --git a/visitor/README.md b/visitor/README.md index c1e24a624..712abad87 100644 --- a/visitor/README.md +++ b/visitor/README.md @@ -3,6 +3,7 @@ layout: pattern title: Visitor folder: visitor permalink: /patterns/visitor/ +pumlid: DSR14OGm20NGLhG0mtsxmSWeJa8oyD7sTo_xJczLgoqFIM_B1Spu43c_vLHSkMU8rs4GGwcZaxPy6UnqyyFR8Q6dRPC1SGlg7B_Gew4OJeBwVqdlPMPlNm00 categories: Behavioral tags: - Java From 5c1a4f1caf8145ca8dba90c34a838de53dcd95f5 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Wed, 31 Aug 2016 16:12:13 +0530 Subject: [PATCH 032/492] Added example that mocking frameworks use proxy pattern --- proxy/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/README.md b/proxy/README.md index 1c22c0710..a3cdbf788 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -41,6 +41,7 @@ are several common situations in which the Proxy pattern is applicable * [java.lang.reflect.Proxy](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html) * [Apache Commons Proxy](https://commons.apache.org/proper/commons-proxy/) +* Mocking frameworks Mockito, Powermock, EasyMock ## Credits From e425c2ef2f721600e14b59d67eb5ef27759113f0 Mon Sep 17 00:00:00 2001 From: Markus Moser Date: Wed, 31 Aug 2016 13:15:44 +0200 Subject: [PATCH 033/492] Add webhook for travis build failures to gitter Only the core group (private) gitter room --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index bcbad6827..aed6ef420 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,5 +18,11 @@ after_success: notifications: email: - iluwatar@gmail.com + webhooks: + urls: + - https://webhooks.gitter.im/e/3319623945358a093a6f + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: never # options: [always|never|change] default: always sudo: false # route the build to the container-based infrastructure for a faster build From 90c636abd312c40fee22c2bf7dc3c057e811ce75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 2 Sep 2016 21:28:45 +0300 Subject: [PATCH 034/492] Add missing license headers --- _scripts/postPumlsToServer.py | 23 +++++++++++++++++++ .../java/com/iluwatar/promise/Utility.java | 22 ++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/_scripts/postPumlsToServer.py b/_scripts/postPumlsToServer.py index 2f975d3d8..3929b3c86 100644 --- a/_scripts/postPumlsToServer.py +++ b/_scripts/postPumlsToServer.py @@ -1,3 +1,26 @@ +# +# The MIT License +# Copyright (c) 2014 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. +# + import requests, glob, re, os # taken from here: http://stackoverflow.com/a/13641746 diff --git a/promise/src/main/java/com/iluwatar/promise/Utility.java b/promise/src/main/java/com/iluwatar/promise/Utility.java index 8d5be2538..d451600a3 100644 --- a/promise/src/main/java/com/iluwatar/promise/Utility.java +++ b/promise/src/main/java/com/iluwatar/promise/Utility.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.promise; import java.io.BufferedReader; From be2c7fdb2bf4279c6482cb794c1389ae9e83b7e9 Mon Sep 17 00:00:00 2001 From: NooBxGockeL Date: Fri, 2 Sep 2016 23:15:38 +0200 Subject: [PATCH 035/492] Update URM version: 1.4.0 -> 1.4.1, fixes #492 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 777ec6b69..302346993 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 4.12.1 4.5.2 2.22 - 1.4.0 + 1.4.1 abstract-factory From 165d1f12986cd5d0735a4fb667a14dda905012ec Mon Sep 17 00:00:00 2001 From: Markus Moser Date: Fri, 2 Sep 2016 23:54:52 +0200 Subject: [PATCH 036/492] Turn Error Tracing on when installing Travis currently errors and i cant reproduce locally, so this might help finding the culprit --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index aed6ef420..c502e8a99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,10 @@ before_install: - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start +# default install command is just "mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V" +install: +- mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -e + after_success: - mvn clean test jacoco:report coveralls:report - bash update-ghpages.sh From fa52a7f77eb038cf7e67bf9dfa32089b1fec096b Mon Sep 17 00:00:00 2001 From: Markus Moser Date: Sat, 3 Sep 2016 00:19:50 +0200 Subject: [PATCH 037/492] Run build with latest java 8 release --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index c502e8a99..19d4614f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,11 @@ after_success: - mvn clean test jacoco:report coveralls:report - bash update-ghpages.sh +addons: + apt: + packages: + - oracle-java8-installer + notifications: email: - iluwatar@gmail.com From ff23e90c4f6e08127c3b0b33539531f4c07e4724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 3 Sep 2016 08:43:35 +0300 Subject: [PATCH 038/492] Add puml for Promise pattern --- promise/etc/promise.urm.puml | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 promise/etc/promise.urm.puml diff --git a/promise/etc/promise.urm.puml b/promise/etc/promise.urm.puml new file mode 100644 index 000000000..d97871411 --- /dev/null +++ b/promise/etc/promise.urm.puml @@ -0,0 +1,77 @@ +@startuml +package com.iluwatar.promise { + ~class PromiseSupport { + - COMPLETED : int {static} + - FAILED : int {static} + - RUNNING : int {static} + - exception : Exception + - lock : Object + - state : int + - value : T + ~ PromiseSupport() + + cancel(mayInterruptIfRunning : boolean) : boolean + ~ fulfill(value : T) + ~ fulfillExceptionally(exception : Exception) + + get() : T + + get(timeout : long, unit : TimeUnit) : T + + isCancelled() : boolean + + isDone() : boolean + } + -class ConsumeAction { + - action : Consumer + - dest : Promise + - src : Promise + - ConsumeAction(src : Promise, dest : Promise, action : Consumer) + + run() + } + -class TransformAction { + - dest : Promise + - func : Function + - src : Promise + - TransformAction(src : Promise, dest : Promise, func : Function) + + run() + } + class App { + - DEFAULT_URL : String {static} + - executor : ExecutorService + - stopLatch : CountDownLatch + - App() + - calculateLineCount() + - calculateLowestFrequencyChar() + - characterFrequency() : Promise> + - countLines() : Promise + - download(urlString : String) : Promise + - lowestFrequencyChar() : Promise + + main(args : String[]) {static} + - promiseUsage() + - stop() + - taskCompleted() + } + class Promise { + - exceptionHandler : Consumer + - fulfillmentAction : Runnable + + Promise() + + fulfill(value : T) + + fulfillExceptionally(exception : Exception) + + fulfillInAsync(task : Callable, executor : Executor) : Promise + - handleException(exception : Exception) + + onError(exceptionHandler : Consumer) : Promise + - postFulfillment() + + thenAccept(action : Consumer) : Promise + + thenApply(func : Function) : Promise + } + class Utility { + + Utility() + + characterFrequency(fileLocation : String) : Map {static} + + countLines(fileLocation : String) : Integer {static} + + downloadFile(urlString : String) : String {static} + + lowestFrequencyChar(charFrequency : Map) : Character {static} + } +} +TransformAction --+ Promise +TransformAction --> "-src" Promise +ConsumeAction --+ Promise +ConsumeAction --> "-src" Promise +Utility --+ Map +Promise --|> PromiseSupport +@enduml \ No newline at end of file From 2d9906190221ff46ed796b6526e0ce1631623828 Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 8 Aug 2016 23:31:41 +0100 Subject: [PATCH 039/492] Issue #469: Implementation of Event-based Asynchronous pattern --- event-asynchronous/README.md | 28 +++ event-asynchronous/etc/event-asynchronous.png | Bin 0 -> 31413 bytes .../etc/event-asynchronous.ucls | 110 +++++++++++ event-asynchronous/pom.xml | 42 ++++ .../com/iluwatar/event/asynchronous/App.java | 185 ++++++++++++++++++ .../iluwatar/event/asynchronous/Event.java | 88 +++++++++ .../EventDoesNotExistException.java | 26 +++ .../event/asynchronous/EventManager.java | 148 ++++++++++++++ .../iluwatar/event/asynchronous/IEvent.java | 27 +++ .../InvalidOperationException.java | 27 +++ .../LongRunningEventException.java | 26 +++ .../MaxNumOfEventsAllowedException.java | 26 +++ .../asynchronous/ThreadCompleteListener.java | 21 ++ .../src/main/java/config.properties | 1 + .../iluwatar/event/asynchronous/AppTest.java | 32 +++ .../asynchronous/EventAsynchronousTest.java | 73 +++++++ 16 files changed, 860 insertions(+) create mode 100644 event-asynchronous/README.md create mode 100644 event-asynchronous/etc/event-asynchronous.png create mode 100644 event-asynchronous/etc/event-asynchronous.ucls create mode 100644 event-asynchronous/pom.xml create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java create mode 100644 event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java create mode 100644 event-asynchronous/src/main/java/config.properties create mode 100644 event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java create mode 100644 event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java diff --git a/event-asynchronous/README.md b/event-asynchronous/README.md new file mode 100644 index 000000000..59e6e8b33 --- /dev/null +++ b/event-asynchronous/README.md @@ -0,0 +1,28 @@ +--- +layout: pattern +title: Event-based Asynchronous +folder: event-asynchronous +permalink: /patterns/event-asynchronous/ +categories: Other +tags: + - Java +--- + +## Intent +The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many +of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:- +(1) Perform time-consuming tasks, such as downloads and database operations, "in the background," without interrupting your application. +(2) Execute multiple operations simultaneously, receiving notifications when each completes. +(3) Wait for resources to become available without stopping ("hanging") your application. +(4) Communicate with pending asynchronous operations using the familiar events-and-delegates model. + +![alt text](./etc/event-asynchronous.png "Event-based Asynchronous") + +## Applicability +Use the Event-based Asynchronous pattern(s) when + +* Time-consuming tasks are needed to run in the background without disrupting the current application. + +## Credits + +* [Event-based Asynchronous Pattern Overview](https://msdn.microsoft.com/en-us/library/wewwczdw%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) diff --git a/event-asynchronous/etc/event-asynchronous.png b/event-asynchronous/etc/event-asynchronous.png new file mode 100644 index 0000000000000000000000000000000000000000..a46ffe1c5d17773d38dac792349cc547adc06955 GIT binary patch literal 31413 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml new file mode 100644 index 000000000..60ab8f0aa --- /dev/null +++ b/event-asynchronous/pom.xml @@ -0,0 +1,42 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.13.0-SNAPSHOT + + event-asynchronous + + + junit + junit + test + + + diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java new file mode 100644 index 000000000..3375fd4ec --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java @@ -0,0 +1,185 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import java.util.Scanner; + +/** + * + * This application demonstrates the Event-based Asynchronous pattern. Essentially, users (of the pattern) may + * choose to run events in an Asynchronous or Synchronous mode. There can be multiple Asynchronous events running at + * once but only one Synchronous event can run at a time. Asynchronous events are synonymous to multi-threads. The key + * point here is that the threads run in the background and the user is free to carry on with other processes. Once an + * event is complete, the appropriate listener/callback method will be called. The listener then proceeds to carry out + * further processing depending on the needs of the user. + * + * The {@link EventManager} manages the events/threads that the user creates. Currently, the supported event operations + * are: start, stop, getStatus. For Synchronous events, the user is unable to + * start another (Synchronous) event if one is already running at the time. The running event would have to either be + * stopped or completed before a new event can be started. + * + * The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many + * of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:- + * (1) Perform time-consuming tasks, such as downloads and database operations, "in the background," without + * interrupting your application. (2) Execute multiple operations simultaneously, receiving notifications when each + * completes. (3) Wait for resources to become available without stopping ("hanging") your application. (4) Communicate + * with pending asynchronous operations using the familiar events-and-delegates model. + * + * @see EventManager + * @see Event + * + */ +public class App { + + boolean interactiveMode = false; + + public static void main(String[] args) { + App app = new App(); + + app.setUp(); + app.run(); + } + + /** + * App can run in interactive mode or not. Interactive mode == Allow user interaction with command line. + * Non-interactive is a quick sequential run through the available {@link EventManager} operations. + */ + public void setUp() { + Properties prop = new Properties(); + String propFileName = "config.properties"; + + InputStream inputStream = App.class.getClassLoader().getResourceAsStream(propFileName); + + if (inputStream != null) { + try { + prop.load(inputStream); + } catch (IOException e) { + } + String property = prop.getProperty("INTERACTIVE_MODE"); + if (property.equalsIgnoreCase("YES")) { + interactiveMode = true; + } + } + } + + public void run() { + if (interactiveMode) { + runInteractiveMode(); + } else { + quickRun(); + } + } + + public void quickRun() { + EventManager eventManager = new EventManager(); + + try { + // Create an Asynchronous event. + int aEventID = eventManager.createAsyncEvent(60); + System.out.println("Event [" + aEventID + "] has been created."); + eventManager.startEvent(aEventID); + System.out.println("Event [" + aEventID + "] has been started."); + + // Create a Synchronous event. + int sEventID = eventManager.createSyncEvent(60); + System.out.println("Event [" + sEventID + "] has been created."); + eventManager.startEvent(sEventID); + System.out.println("Event [" + sEventID + "] has been started."); + + eventManager.getStatus(aEventID); + eventManager.getStatus(sEventID); + + eventManager.stopEvent(aEventID); + System.out.println("Event [" + aEventID + "] has been stopped."); + eventManager.stopEvent(sEventID); + System.out.println("Event [" + sEventID + "] has been stopped."); + + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException + | InvalidOperationException e) { + System.out.println(e.getMessage()); + } + } + + public void runInteractiveMode() { + EventManager eventManager = new EventManager(); + + Scanner s = new Scanner(System.in); + int option = 0; + option = -1; + while (option != 5) { + System.out + .println("(1) START_EVENT \n(2) STOP_EVENT \n(3) STATUS_OF_EVENT \n(4) STATUS_OF_ALL_EVENTS \n(5) EXIT"); + System.out.print("Choose [1,2,3,4,5]: "); + option = s.nextInt(); + + if (option == 1) { + s.nextLine(); + System.out.print("(A)sync or (S)ync event?: "); + String eventType = s.nextLine(); + System.out.print("How long should this event run for (in seconds)?: "); + int eventTime = s.nextInt(); + if (eventType.equalsIgnoreCase("A")) { + try { + int eventID = eventManager.createAsyncEvent(eventTime); + System.out.println("Event [" + eventID + "] has been created."); + eventManager.startEvent(eventID); + System.out.println("Event [" + eventID + "] has been started."); + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { + System.out.println(e.getMessage()); + } + } else if (eventType.equalsIgnoreCase("S")) { + try { + int eventID = eventManager.createSyncEvent(eventTime); + System.out.println("Event [" + eventID + "] has been created."); + eventManager.startEvent(eventID); + System.out.println("Event [" + eventID + "] has been started."); + } catch (MaxNumOfEventsAllowedException | InvalidOperationException | LongRunningEventException + | EventDoesNotExistException e) { + System.out.println(e.getMessage()); + } + } else { + System.out.println("Unknown event type."); + } + } else if (option == 2) { + System.out.print("Event ID: "); + int eventID = s.nextInt(); + try { + eventManager.stopEvent(eventID); + System.out.println("Event [" + eventID + "] has been stopped."); + } catch (EventDoesNotExistException e) { + System.out.println(e.getMessage()); + } + } else if (option == 3) { + System.out.print("Event ID: "); + int eventID = s.nextInt(); + try { + eventManager.getStatus(eventID); + } catch (EventDoesNotExistException e) { + System.out.println(e.getMessage()); + } + } else if (option == 4) { + eventManager.getStatusOfAllEvents(); + } + } + + s.close(); + } + +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java new file mode 100644 index 000000000..48dc37236 --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java @@ -0,0 +1,88 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +/** + * + * Each Event runs as a separate/individual thread. + * + */ +public class Event implements IEvent, Runnable { + + private int eventID; + private int eventTime; + private Thread thread; + private long counter = 0; + private boolean isComplete = false; + private ThreadCompleteListener eventListener; + + public Event(int eventID, int eventTime) { + this.eventID = eventID; + this.eventTime = eventTime; + } + + @Override + public void start() { + thread = new Thread(this); + thread.start(); + } + + @Override + public void stop() { + thread.interrupt(); + } + + @Override + public void status() { + if (!isComplete) { + System.out.println("[" + eventID + "] I am at not done. [" + counter + "%]"); + } else { + System.out.println("[" + eventID + "] I am done."); + } + } + + @Override + public void run() { + long currentTime = System.currentTimeMillis(); + long endTime = currentTime + (eventTime * 1000); + while (System.currentTimeMillis() < endTime) { + try { + counter += 1; + Thread.sleep(5000); // Sleep for 5 seconds. + } catch (InterruptedException e) { + return; + } + } + isComplete = true; + notifyListener(); + } + + public final void addListener(final ThreadCompleteListener listener) { + this.eventListener = listener; + } + + public final void removeListener(final ThreadCompleteListener listener) { + this.eventListener = null; + } + + private final void notifyListener() { + if (eventListener != null) { + eventListener.notifyOfThreadComplete(eventID); + } + } + +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java new file mode 100644 index 000000000..77c1d479b --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java @@ -0,0 +1,26 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +public class EventDoesNotExistException extends Exception { + + private static final long serialVersionUID = -3398463738273811509L; + + public EventDoesNotExistException(String message) { + super(message); + } +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java new file mode 100644 index 000000000..305548111 --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java @@ -0,0 +1,148 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +import java.util.Iterator; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * EventManager handles and maintains a pool of event threads. {@link Event} threads are created upon user request. Thre + * are two types of events; Asynchronous and Synchronous. There can be multiple Asynchronous events running at once but + * only one Synchronous event running at a time. Currently supported event operations are: start, stop, and getStatus. + * Once an event is complete, it then notifies EventManager through a listener. The EventManager then takes the event + * out of the pool. + * + */ +public class EventManager implements ThreadCompleteListener { + + private int minID = 1; + private int maxID = Integer.MAX_VALUE - 1; // Be cautious of overflows. + private int maxRunningEvents = 1000; // no particular reason. Just don't wanna have too many running events. :) + private int maxEventTime = 1800; // in seconds / 30 minutes. + private int currentlyRunningSyncEvent = -1; + private Random rand; + private Map eventPool; + + public EventManager() { + rand = new Random(1); + eventPool = new ConcurrentHashMap(maxRunningEvents); + + } + + // Create a Synchronous event. + public int createSyncEvent(int eventTime) + throws MaxNumOfEventsAllowedException, InvalidOperationException, LongRunningEventException { + int eventID = createEvent(eventTime); + if (currentlyRunningSyncEvent != -1) { + throw new InvalidOperationException( + "Event [" + currentlyRunningSyncEvent + "] is still running. Please wait until it finishes and try again."); + } + currentlyRunningSyncEvent = eventID; + + return eventID; + } + + // Create an Asynchronous event. + public int createAsyncEvent(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { + return createEvent(eventTime); + } + + private int createEvent(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { + if (eventPool.size() == maxRunningEvents) { + throw new MaxNumOfEventsAllowedException("Too many events are running at the moment. Please try again later."); + } + + if (eventTime >= maxEventTime) { + throw new LongRunningEventException( + "Maximum event time allowed is " + maxEventTime + " seconds. Please try again."); + } + + int newEventID = generateID(); + + Event newEvent = new Event(newEventID, eventTime); + newEvent.addListener(this); + eventPool.put(newEventID, newEvent); + + return newEventID; + } + + public void startEvent(int eventID) throws EventDoesNotExistException { + if (!eventPool.containsKey(eventID)) { + throw new EventDoesNotExistException(eventID + " does not exist."); + } + + eventPool.get(eventID).start(); + } + + public void stopEvent(int eventID) throws EventDoesNotExistException { + if (!eventPool.containsKey(eventID)) { + throw new EventDoesNotExistException(eventID + " does not exist."); + } + + if (eventID == currentlyRunningSyncEvent) { + currentlyRunningSyncEvent = -1; + } + + eventPool.get(eventID).stop(); + eventPool.remove(eventID); + } + + public void getStatus(int eventID) throws EventDoesNotExistException { + if (!eventPool.containsKey(eventID)) { + throw new EventDoesNotExistException(eventID + " does not exist."); + } + + eventPool.get(eventID).status(); + } + + @SuppressWarnings("rawtypes") + public void getStatusOfAllEvents() { + Iterator it = eventPool.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + ((Event) pair.getValue()).status(); + } + } + + /** + * Returns a pseudo-random number between min and max, inclusive. The difference between min and max can be at most + * Integer.MAX_VALUE - 1. + */ + private int generateID() { + // nextInt is normally exclusive of the top value, + // so add 1 to make it inclusive + int randomNum = rand.nextInt((maxID - minID) + 1) + minID; + while (eventPool.containsKey(randomNum)) { + randomNum = rand.nextInt((maxID - minID) + 1) + minID; + } + + return randomNum; + } + + /** + * Callback from an {@link Event} (once it is complete). The Event is then removed from the pool. + */ + @Override + public void notifyOfThreadComplete(int eventID) { + eventPool.get(eventID).status(); + eventPool.remove(eventID); + } + +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java new file mode 100644 index 000000000..448c02e84 --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java @@ -0,0 +1,27 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +public interface IEvent { + + public void start(); + + public void stop(); + + public void status(); + +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java new file mode 100644 index 000000000..4fd5b0eed --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java @@ -0,0 +1,27 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +public class InvalidOperationException extends Exception { + + private static final long serialVersionUID = -6191545255213410803L; + + public InvalidOperationException(String message) { + super(message); + } + +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java new file mode 100644 index 000000000..6817b1dd8 --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java @@ -0,0 +1,26 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +public class LongRunningEventException extends Exception { + + private static final long serialVersionUID = -483423544320148809L; + + public LongRunningEventException(String message) { + super(message); + } +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java new file mode 100644 index 000000000..9f8f2891c --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java @@ -0,0 +1,26 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +public class MaxNumOfEventsAllowedException extends Exception { + + private static final long serialVersionUID = -8430876973516292695L; + + public MaxNumOfEventsAllowedException(String message) { + super(message); + } +} diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java new file mode 100644 index 000000000..e5c910289 --- /dev/null +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java @@ -0,0 +1,21 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +public interface ThreadCompleteListener { + void notifyOfThreadComplete(final int eventID); +} diff --git a/event-asynchronous/src/main/java/config.properties b/event-asynchronous/src/main/java/config.properties new file mode 100644 index 000000000..edbe90e05 --- /dev/null +++ b/event-asynchronous/src/main/java/config.properties @@ -0,0 +1 @@ +INTERACTIVE_MODE=NO \ No newline at end of file diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java new file mode 100644 index 000000000..8736fcf77 --- /dev/null +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/AppTest.java @@ -0,0 +1,32 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +import java.io.IOException; + +import org.junit.Test; + +/** + * Tests that EventAsynchronous example runs without errors. + */ +public class AppTest { + @Test + public void test() throws IOException { + String[] args = {}; + App.main(args); + } +} diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java new file mode 100644 index 000000000..0ab901106 --- /dev/null +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java @@ -0,0 +1,73 @@ +/** + * The MIT License Copyright (c) 2014 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.event.asynchronous; + +import org.junit.Before; +import org.junit.Test; + +/** + * + * Application test + * + */ +public class EventAsynchronousTest { + App app; + + @Before + public void setUp() { + app = new App(); + } + + @Test + public void testAsynchronousEvent() { + EventManager eventManager = new EventManager(); + try { + int aEventID = eventManager.createAsyncEvent(60); + eventManager.startEvent(aEventID); + eventManager.stopEvent(aEventID); + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testSynchronousEvent() { + EventManager eventManager = new EventManager(); + try { + int sEventID = eventManager.createSyncEvent(60); + eventManager.startEvent(sEventID); + eventManager.stopEvent(sEventID); + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException + | InvalidOperationException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testUnsuccessfulSynchronousEvent() { + EventManager eventManager = new EventManager(); + try { + int sEventID = eventManager.createSyncEvent(60); + eventManager.startEvent(sEventID); + sEventID = eventManager.createSyncEvent(60); + eventManager.startEvent(sEventID); + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException + | InvalidOperationException e) { + System.out.println(e.getMessage()); + } + } +} From e1836fee2f3fe7944faf89ff1b66b137294492ed Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 8 Aug 2016 23:44:39 +0100 Subject: [PATCH 040/492] Updated parent POM to include new pattern (Event-asynchronous) --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 302346993..058dee5a1 100644 --- a/pom.xml +++ b/pom.xml @@ -131,6 +131,7 @@ aggregator-microservices promise page-object + event-asynchronous From f11597136f8bebdcb208a141f8e0fd47ee4dbd1e Mon Sep 17 00:00:00 2001 From: WSSIA Date: Tue, 9 Aug 2016 00:32:05 +0100 Subject: [PATCH 041/492] Fixed Checkstyle errors. --- .../com/iluwatar/event/asynchronous/App.java | 69 +++++++----- .../iluwatar/event/asynchronous/Event.java | 12 +-- .../event/asynchronous/EventManager.java | 102 ++++++++++++------ .../asynchronous/ThreadCompleteListener.java | 2 +- .../asynchronous/EventAsynchronousTest.java | 20 ++-- 5 files changed, 130 insertions(+), 75 deletions(-) diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java index 3375fd4ec..fa6116b46 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java @@ -50,6 +50,11 @@ public class App { boolean interactiveMode = false; + /** + * Program entry point. + * + * @param args command line args + */ public static void main(String[] args) { App app = new App(); @@ -71,6 +76,7 @@ public class App { try { prop.load(inputStream); } catch (IOException e) { + System.out.println(propFileName + " was not found. Defaulting to non-interactive mode."); } String property = prop.getProperty("INTERACTIVE_MODE"); if (property.equalsIgnoreCase("YES")) { @@ -79,6 +85,9 @@ public class App { } } + /** + * Run program in either interactive mode or not. + */ public void run() { if (interactiveMode) { runInteractiveMode(); @@ -87,29 +96,32 @@ public class App { } } + /** + * Run program in non-interactive mode. + */ public void quickRun() { EventManager eventManager = new EventManager(); try { // Create an Asynchronous event. - int aEventID = eventManager.createAsyncEvent(60); - System.out.println("Event [" + aEventID + "] has been created."); - eventManager.startEvent(aEventID); - System.out.println("Event [" + aEventID + "] has been started."); + int aEventId = eventManager.createAsyncEvent(60); + System.out.println("Event [" + aEventId + "] has been created."); + eventManager.startEvent(aEventId); + System.out.println("Event [" + aEventId + "] has been started."); // Create a Synchronous event. - int sEventID = eventManager.createSyncEvent(60); - System.out.println("Event [" + sEventID + "] has been created."); - eventManager.startEvent(sEventID); - System.out.println("Event [" + sEventID + "] has been started."); + int sEventId = eventManager.createSyncEvent(60); + System.out.println("Event [" + sEventId + "] has been created."); + eventManager.startEvent(sEventId); + System.out.println("Event [" + sEventId + "] has been started."); - eventManager.getStatus(aEventID); - eventManager.getStatus(sEventID); + eventManager.getStatus(aEventId); + eventManager.getStatus(sEventId); - eventManager.stopEvent(aEventID); - System.out.println("Event [" + aEventID + "] has been stopped."); - eventManager.stopEvent(sEventID); - System.out.println("Event [" + sEventID + "] has been stopped."); + eventManager.stopEvent(aEventId); + System.out.println("Event [" + aEventId + "] has been stopped."); + eventManager.stopEvent(sEventId); + System.out.println("Event [" + sEventId + "] has been stopped."); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { @@ -117,6 +129,9 @@ public class App { } } + /** + * Run program in interactive mode. + */ public void runInteractiveMode() { EventManager eventManager = new EventManager(); @@ -137,19 +152,19 @@ public class App { int eventTime = s.nextInt(); if (eventType.equalsIgnoreCase("A")) { try { - int eventID = eventManager.createAsyncEvent(eventTime); - System.out.println("Event [" + eventID + "] has been created."); - eventManager.startEvent(eventID); - System.out.println("Event [" + eventID + "] has been started."); + int eventId = eventManager.createAsyncEvent(eventTime); + System.out.println("Event [" + eventId + "] has been created."); + eventManager.startEvent(eventId); + System.out.println("Event [" + eventId + "] has been started."); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { System.out.println(e.getMessage()); } } else if (eventType.equalsIgnoreCase("S")) { try { - int eventID = eventManager.createSyncEvent(eventTime); - System.out.println("Event [" + eventID + "] has been created."); - eventManager.startEvent(eventID); - System.out.println("Event [" + eventID + "] has been started."); + int eventId = eventManager.createSyncEvent(eventTime); + System.out.println("Event [" + eventId + "] has been created."); + eventManager.startEvent(eventId); + System.out.println("Event [" + eventId + "] has been started."); } catch (MaxNumOfEventsAllowedException | InvalidOperationException | LongRunningEventException | EventDoesNotExistException e) { System.out.println(e.getMessage()); @@ -159,18 +174,18 @@ public class App { } } else if (option == 2) { System.out.print("Event ID: "); - int eventID = s.nextInt(); + int eventId = s.nextInt(); try { - eventManager.stopEvent(eventID); - System.out.println("Event [" + eventID + "] has been stopped."); + eventManager.stopEvent(eventId); + System.out.println("Event [" + eventId + "] has been stopped."); } catch (EventDoesNotExistException e) { System.out.println(e.getMessage()); } } else if (option == 3) { System.out.print("Event ID: "); - int eventID = s.nextInt(); + int eventId = s.nextInt(); try { - eventManager.getStatus(eventID); + eventManager.getStatus(eventId); } catch (EventDoesNotExistException e) { System.out.println(e.getMessage()); } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java index 48dc37236..4b4fe1d94 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java @@ -23,15 +23,15 @@ package com.iluwatar.event.asynchronous; */ public class Event implements IEvent, Runnable { - private int eventID; + private int eventId; private int eventTime; private Thread thread; private long counter = 0; private boolean isComplete = false; private ThreadCompleteListener eventListener; - public Event(int eventID, int eventTime) { - this.eventID = eventID; + public Event(int eventId, int eventTime) { + this.eventId = eventId; this.eventTime = eventTime; } @@ -49,9 +49,9 @@ public class Event implements IEvent, Runnable { @Override public void status() { if (!isComplete) { - System.out.println("[" + eventID + "] I am at not done. [" + counter + "%]"); + System.out.println("[" + eventId + "] I am at not done. [" + counter + "%]"); } else { - System.out.println("[" + eventID + "] I am done."); + System.out.println("[" + eventId + "] I am done."); } } @@ -81,7 +81,7 @@ public class Event implements IEvent, Runnable { private final void notifyListener() { if (eventListener != null) { - eventListener.notifyOfThreadComplete(eventID); + eventListener.notifyOfThreadComplete(eventId); } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java index 305548111..d3278594f 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java @@ -32,34 +32,53 @@ import java.util.concurrent.ConcurrentHashMap; */ public class EventManager implements ThreadCompleteListener { - private int minID = 1; - private int maxID = Integer.MAX_VALUE - 1; // Be cautious of overflows. + private int minId = 1; + private int maxId = Integer.MAX_VALUE - 1; // Be cautious of overflows. private int maxRunningEvents = 1000; // no particular reason. Just don't wanna have too many running events. :) private int maxEventTime = 1800; // in seconds / 30 minutes. private int currentlyRunningSyncEvent = -1; private Random rand; private Map eventPool; + /** + * EventManager constructor. + * + */ public EventManager() { rand = new Random(1); eventPool = new ConcurrentHashMap(maxRunningEvents); } - // Create a Synchronous event. + /** + * Create a Synchronous event. + * + * @param eventTime Time an event should run for. + * @return eventId + * @throws MaxNumOfEventsAllowedException When too many events are running at a time. + * @throws InvalidOperationException No new synchronous events can be created when one is already running. + * @throws LongRunningEventException Long running events are not allowed in the app. + */ public int createSyncEvent(int eventTime) throws MaxNumOfEventsAllowedException, InvalidOperationException, LongRunningEventException { - int eventID = createEvent(eventTime); + int eventId = createEvent(eventTime); if (currentlyRunningSyncEvent != -1) { throw new InvalidOperationException( "Event [" + currentlyRunningSyncEvent + "] is still running. Please wait until it finishes and try again."); } - currentlyRunningSyncEvent = eventID; + currentlyRunningSyncEvent = eventId; - return eventID; + return eventId; } - // Create an Asynchronous event. + /** + * Create an Asynchronous event. + * + * @param eventTime Time an event should run for. + * @return eventId + * @throws MaxNumOfEventsAllowedException When too many events are running at a time. + * @throws LongRunningEventException Long running events are not allowed in the app. + */ public int createAsyncEvent(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { return createEvent(eventTime); } @@ -74,44 +93,65 @@ public class EventManager implements ThreadCompleteListener { "Maximum event time allowed is " + maxEventTime + " seconds. Please try again."); } - int newEventID = generateID(); + int newEventId = generateId(); - Event newEvent = new Event(newEventID, eventTime); + Event newEvent = new Event(newEventId, eventTime); newEvent.addListener(this); - eventPool.put(newEventID, newEvent); + eventPool.put(newEventId, newEvent); - return newEventID; + return newEventId; } - public void startEvent(int eventID) throws EventDoesNotExistException { - if (!eventPool.containsKey(eventID)) { - throw new EventDoesNotExistException(eventID + " does not exist."); + /** + * Starts event. + * + * @param eventId The event that needs to be started. + * @throws EventDoesNotExistException If event does not exist in our eventPool. + */ + public void startEvent(int eventId) throws EventDoesNotExistException { + if (!eventPool.containsKey(eventId)) { + throw new EventDoesNotExistException(eventId + " does not exist."); } - eventPool.get(eventID).start(); + eventPool.get(eventId).start(); } - public void stopEvent(int eventID) throws EventDoesNotExistException { - if (!eventPool.containsKey(eventID)) { - throw new EventDoesNotExistException(eventID + " does not exist."); + /** + * Stops event. + * + * @param eventId The event that needs to be stopped. + * @throws EventDoesNotExistException If event does not exist in our eventPool. + */ + public void stopEvent(int eventId) throws EventDoesNotExistException { + if (!eventPool.containsKey(eventId)) { + throw new EventDoesNotExistException(eventId + " does not exist."); } - if (eventID == currentlyRunningSyncEvent) { + if (eventId == currentlyRunningSyncEvent) { currentlyRunningSyncEvent = -1; } - eventPool.get(eventID).stop(); - eventPool.remove(eventID); + eventPool.get(eventId).stop(); + eventPool.remove(eventId); } - public void getStatus(int eventID) throws EventDoesNotExistException { - if (!eventPool.containsKey(eventID)) { - throw new EventDoesNotExistException(eventID + " does not exist."); + /** + * Get status of a running event. + * + * @param eventId The event to inquire status of. + * @throws EventDoesNotExistException If event does not exist in our eventPool. + */ + public void getStatus(int eventId) throws EventDoesNotExistException { + if (!eventPool.containsKey(eventId)) { + throw new EventDoesNotExistException(eventId + " does not exist."); } - eventPool.get(eventID).status(); + eventPool.get(eventId).status(); } + /** + * Gets status of all running events. + */ @SuppressWarnings("rawtypes") public void getStatusOfAllEvents() { Iterator it = eventPool.entrySet().iterator(); @@ -125,12 +165,12 @@ public class EventManager implements ThreadCompleteListener { * Returns a pseudo-random number between min and max, inclusive. The difference between min and max can be at most * Integer.MAX_VALUE - 1. */ - private int generateID() { + private int generateId() { // nextInt is normally exclusive of the top value, // so add 1 to make it inclusive - int randomNum = rand.nextInt((maxID - minID) + 1) + minID; + int randomNum = rand.nextInt((maxId - minId) + 1) + minId; while (eventPool.containsKey(randomNum)) { - randomNum = rand.nextInt((maxID - minID) + 1) + minID; + randomNum = rand.nextInt((maxId - minId) + 1) + minId; } return randomNum; @@ -140,9 +180,9 @@ public class EventManager implements ThreadCompleteListener { * Callback from an {@link Event} (once it is complete). The Event is then removed from the pool. */ @Override - public void notifyOfThreadComplete(int eventID) { - eventPool.get(eventID).status(); - eventPool.remove(eventID); + public void notifyOfThreadComplete(int eventId) { + eventPool.get(eventId).status(); + eventPool.remove(eventId); } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java index e5c910289..88f300634 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java @@ -17,5 +17,5 @@ package com.iluwatar.event.asynchronous; public interface ThreadCompleteListener { - void notifyOfThreadComplete(final int eventID); + void notifyOfThreadComplete(final int eventId); } diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java index 0ab901106..392c7fba6 100644 --- a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java @@ -36,9 +36,9 @@ public class EventAsynchronousTest { public void testAsynchronousEvent() { EventManager eventManager = new EventManager(); try { - int aEventID = eventManager.createAsyncEvent(60); - eventManager.startEvent(aEventID); - eventManager.stopEvent(aEventID); + int aEventId = eventManager.createAsyncEvent(60); + eventManager.startEvent(aEventId); + eventManager.stopEvent(aEventId); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { System.out.println(e.getMessage()); } @@ -48,9 +48,9 @@ public class EventAsynchronousTest { public void testSynchronousEvent() { EventManager eventManager = new EventManager(); try { - int sEventID = eventManager.createSyncEvent(60); - eventManager.startEvent(sEventID); - eventManager.stopEvent(sEventID); + int sEventId = eventManager.createSyncEvent(60); + eventManager.startEvent(sEventId); + eventManager.stopEvent(sEventId); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { System.out.println(e.getMessage()); @@ -61,10 +61,10 @@ public class EventAsynchronousTest { public void testUnsuccessfulSynchronousEvent() { EventManager eventManager = new EventManager(); try { - int sEventID = eventManager.createSyncEvent(60); - eventManager.startEvent(sEventID); - sEventID = eventManager.createSyncEvent(60); - eventManager.startEvent(sEventID); + int sEventId = eventManager.createSyncEvent(60); + eventManager.startEvent(sEventId); + sEventId = eventManager.createSyncEvent(60); + eventManager.startEvent(sEventId); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { System.out.println(e.getMessage()); From 233f1e69f9401611967c8be6cc70f16d2ac18e1b Mon Sep 17 00:00:00 2001 From: WSSIA Date: Tue, 9 Aug 2016 22:00:19 +0100 Subject: [PATCH 042/492] Removed PUBLIC modifiers from IEvent --- .../main/java/com/iluwatar/event/asynchronous/IEvent.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java index 448c02e84..bcd78b6c0 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java @@ -18,10 +18,10 @@ package com.iluwatar.event.asynchronous; public interface IEvent { - public void start(); + void start(); - public void stop(); + void stop(); - public void status(); + void status(); } From ab68129829b227cf6ac5637538775219a8463ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 3 Sep 2016 22:02:08 +0300 Subject: [PATCH 043/492] Hexagonal pattern: move business logic to core --- .../administration/LotteryAdministration.java | 4 +- .../LotteryAdministrationImpl.java | 47 ++------ .../hexagonal/domain/LotterySystem.java | 58 ++++++++++ .../hexagonal/domain/LotterySystemImpl.java | 107 ++++++++++++++++++ .../hexagonal/service/LotteryService.java | 4 +- .../hexagonal/service/LotteryServiceImpl.java | 45 ++------ .../{lottery => domain}/LotteryTest.java | 38 +++---- 7 files changed, 202 insertions(+), 101 deletions(-) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java rename hexagonal/src/test/java/com/iluwatar/hexagonal/{lottery => domain}/LotteryTest.java (67%) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java index bc625b230..c6c034ac9 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java @@ -22,12 +22,12 @@ */ package com.iluwatar.hexagonal.administration; -import java.util.Map; - import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; +import java.util.Map; + /** * * Administrator interface for lottery service. diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java index a452600aa..2003849c2 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java @@ -22,22 +22,13 @@ */ package com.iluwatar.hexagonal.administration; -import java.util.Map; - -import com.iluwatar.hexagonal.banking.WireTransfers; -import com.iluwatar.hexagonal.banking.WireTransfersImpl; -import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; -import com.iluwatar.hexagonal.domain.LotteryConstants; import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotterySystem; +import com.iluwatar.hexagonal.domain.LotterySystemImpl; import com.iluwatar.hexagonal.domain.LotteryTicket; -import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; -import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult.CheckResult; import com.iluwatar.hexagonal.domain.LotteryTicketId; -import com.iluwatar.hexagonal.notifications.LotteryNotifications; -import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; -import com.iluwatar.hexagonal.service.LotteryService; -import com.iluwatar.hexagonal.service.LotteryServiceImpl; + +import java.util.Map; /** * @@ -46,42 +37,24 @@ import com.iluwatar.hexagonal.service.LotteryServiceImpl; */ public class LotteryAdministrationImpl implements LotteryAdministration { - private final LotteryTicketRepository repository; - private final LotteryService service = new LotteryServiceImpl(); - private final LotteryNotifications notifications = new LotteryNotificationsImpl(); - private final WireTransfers bank = new WireTransfersImpl(); + private final LotterySystem lotterySystem; + public LotteryAdministrationImpl() { - repository = new LotteryTicketInMemoryRepository(); + lotterySystem = new LotterySystemImpl(); } @Override public Map getAllSubmittedTickets() { - return repository.findAll(); + return lotterySystem.getAllSubmittedTickets(); } @Override public LotteryNumbers performLottery() { - LotteryNumbers numbers = LotteryNumbers.createRandom(); - Map tickets = getAllSubmittedTickets(); - for (LotteryTicketId id: tickets.keySet()) { - LotteryTicketCheckResult result = service.checkTicketForPrize(id, numbers); - if (result.getResult().equals(CheckResult.WIN_PRIZE)) { - boolean transferred = bank.transferFunds(LotteryConstants.PRIZE_AMOUNT, LotteryConstants.SERVICE_BANK_ACCOUNT, - tickets.get(id).getPlayerDetails().getBankAccount()); - if (transferred) { - notifications.notifyPrize(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); - } else { - notifications.notifyPrizeError(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); - } - } else if (result.getResult().equals(CheckResult.NO_PRIZE)) { - notifications.notifyNoWin(tickets.get(id).getPlayerDetails()); - } - } - return numbers; + return lotterySystem.performLottery(); } @Override public void resetLottery() { - repository.deleteAll(); + lotterySystem.resetLottery(); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java new file mode 100644 index 000000000..2ee114556 --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.domain; + +import java.util.Map; +import java.util.Optional; + +/** + * Lottery system interface + */ +public interface LotterySystem { + + /** + * Get all the lottery tickets submitted for lottery + */ + Map getAllSubmittedTickets(); + + /** + * Draw lottery numbers + */ + LotteryNumbers performLottery(); + + /** + * Begin new lottery round + */ + void resetLottery(); + + /** + * Submit lottery ticket to participate in the lottery + */ + Optional submitTicket(LotteryTicket ticket); + + /** + * Check if lottery ticket has won + */ + LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers); + +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java new file mode 100644 index 000000000..a9290520c --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java @@ -0,0 +1,107 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.domain; + +import com.iluwatar.hexagonal.banking.WireTransfers; +import com.iluwatar.hexagonal.banking.WireTransfersImpl; +import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; +import com.iluwatar.hexagonal.database.LotteryTicketRepository; +import com.iluwatar.hexagonal.notifications.LotteryNotifications; +import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; + +import java.util.Map; +import java.util.Optional; + +/** + * Lottery system implementation + */ +public class LotterySystemImpl implements LotterySystem { + + private final LotteryTicketRepository repository; + private final LotteryNotifications notifications = new LotteryNotificationsImpl(); + private final WireTransfers bank = new WireTransfersImpl(); + + public LotterySystemImpl() { + repository = new LotteryTicketInMemoryRepository(); + } + + @Override + public Map getAllSubmittedTickets() { + return repository.findAll(); + } + + @Override + public LotteryNumbers performLottery() { + LotteryNumbers numbers = LotteryNumbers.createRandom(); + Map tickets = getAllSubmittedTickets(); + for (LotteryTicketId id : tickets.keySet()) { + LotteryTicketCheckResult result = checkTicketForPrize(id, numbers); + if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { + boolean transferred = bank.transferFunds(LotteryConstants.PRIZE_AMOUNT, LotteryConstants.SERVICE_BANK_ACCOUNT, + tickets.get(id).getPlayerDetails().getBankAccount()); + if (transferred) { + notifications.notifyPrize(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); + } else { + notifications.notifyPrizeError(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); + } + } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { + notifications.notifyNoWin(tickets.get(id).getPlayerDetails()); + } + } + return numbers; + } + + @Override + public void resetLottery() { + repository.deleteAll(); + } + + @Override + public Optional submitTicket(LotteryTicket ticket) { + boolean result = bank.transferFunds(LotteryConstants.TICKET_PRIZE, ticket.getPlayerDetails().getBankAccount(), + LotteryConstants.SERVICE_BANK_ACCOUNT); + if (result == false) { + notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); + return Optional.empty(); + } + Optional optional = repository.save(ticket); + if (optional.isPresent()) { + notifications.notifyTicketSubmitted(ticket.getPlayerDetails()); + } + return optional; + } + + @Override + public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { + Optional optional = repository.findById(id); + if (optional.isPresent()) { + if (optional.get().getNumbers().equals(winningNumbers)) { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.WIN_PRIZE, 1000); + } else { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.NO_PRIZE); + } + } else { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.TICKET_NOT_SUBMITTED); + } + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java index 0056e794b..ef2202968 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java @@ -22,13 +22,13 @@ */ package com.iluwatar.hexagonal.service; -import java.util.Optional; - import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; import com.iluwatar.hexagonal.domain.LotteryTicketId; +import java.util.Optional; + /** * * Interface for submitting and checking lottery tickets. diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java index 58df1c7c8..5bce62054 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java @@ -22,20 +22,14 @@ */ package com.iluwatar.hexagonal.service; -import java.util.Optional; - -import com.iluwatar.hexagonal.banking.WireTransfers; -import com.iluwatar.hexagonal.banking.WireTransfersImpl; -import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; -import com.iluwatar.hexagonal.domain.LotteryConstants; import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotterySystem; +import com.iluwatar.hexagonal.domain.LotterySystemImpl; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; import com.iluwatar.hexagonal.domain.LotteryTicketId; -import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult.CheckResult; -import com.iluwatar.hexagonal.notifications.LotteryNotifications; -import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; + +import java.util.Optional; /** * @@ -44,45 +38,22 @@ import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; */ public class LotteryServiceImpl implements LotteryService { - private final LotteryTicketRepository repository; - - private final WireTransfers bank = new WireTransfersImpl(); - - private final LotteryNotifications notifications = new LotteryNotificationsImpl(); + private final LotterySystem lotterySystem; /** * Constructor */ public LotteryServiceImpl() { - repository = new LotteryTicketInMemoryRepository(); + lotterySystem = new LotterySystemImpl(); } @Override public Optional submitTicket(LotteryTicket ticket) { - boolean result = bank.transferFunds(LotteryConstants.TICKET_PRIZE, ticket.getPlayerDetails().getBankAccount(), - LotteryConstants.SERVICE_BANK_ACCOUNT); - if (result == false) { - notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); - return Optional.empty(); - } - Optional optional = repository.save(ticket); - if (optional.isPresent()) { - notifications.notifyTicketSubmitted(ticket.getPlayerDetails()); - } - return optional; + return lotterySystem.submitTicket(ticket); } @Override public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { - Optional optional = repository.findById(id); - if (optional.isPresent()) { - if (optional.get().getNumbers().equals(winningNumbers)) { - return new LotteryTicketCheckResult(CheckResult.WIN_PRIZE, 1000); - } else { - return new LotteryTicketCheckResult(CheckResult.NO_PRIZE); - } - } else { - return new LotteryTicketCheckResult(CheckResult.TICKET_NOT_SUBMITTED); - } + return lotterySystem.checkTicketForPrize(id, winningNumbers); } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/lottery/LotteryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java similarity index 67% rename from hexagonal/src/test/java/com/iluwatar/hexagonal/lottery/LotteryTest.java rename to hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java index 27e5bb6e4..59c8c1930 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/lottery/LotteryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.hexagonal.lottery; +package com.iluwatar.hexagonal.domain; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -30,22 +30,15 @@ import java.util.HashSet; import java.util.Map; import java.util.Optional; +import com.iluwatar.hexagonal.domain.*; import org.junit.Before; import org.junit.Test; -import com.iluwatar.hexagonal.administration.LotteryAdministration; -import com.iluwatar.hexagonal.administration.LotteryAdministrationImpl; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.banking.WireTransfersImpl; import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; -import com.iluwatar.hexagonal.domain.LotteryNumbers; -import com.iluwatar.hexagonal.domain.LotteryTicket; -import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult.CheckResult; -import com.iluwatar.hexagonal.domain.LotteryTicketId; -import com.iluwatar.hexagonal.service.LotteryService; -import com.iluwatar.hexagonal.service.LotteryServiceImpl; import com.iluwatar.hexagonal.test.LotteryTestUtils; /** @@ -55,8 +48,7 @@ import com.iluwatar.hexagonal.test.LotteryTestUtils; */ public class LotteryTest { - private final LotteryAdministration admin = new LotteryAdministrationImpl(); - private final LotteryService service = new LotteryServiceImpl(); + private final LotterySystem lotterySystem = new LotterySystemImpl(); private final LotteryTicketRepository repository = new LotteryTicketInMemoryRepository(); private final WireTransfers wireTransfers = new WireTransfersImpl(); @@ -72,34 +64,34 @@ public class LotteryTest { wireTransfers.setFunds("123-12312", 100); // admin resets the lottery - admin.resetLottery(); - assertEquals(admin.getAllSubmittedTickets().size(), 0); + lotterySystem.resetLottery(); + assertEquals(lotterySystem.getAllSubmittedTickets().size(), 0); // players submit the lottery tickets - Optional ticket1 = service.submitTicket(LotteryTestUtils.createLotteryTicket("cvt@bbb.com", + Optional ticket1 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("cvt@bbb.com", "123-12312", "+32425255", new HashSet<>(Arrays.asList(1, 2, 3, 4)))); assertTrue(ticket1.isPresent()); - Optional ticket2 = service.submitTicket(LotteryTestUtils.createLotteryTicket("ant@bac.com", + Optional ticket2 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("ant@bac.com", "123-12312", "+32423455", new HashSet<>(Arrays.asList(11, 12, 13, 14)))); assertTrue(ticket2.isPresent()); - Optional ticket3 = service.submitTicket(LotteryTestUtils.createLotteryTicket("arg@boo.com", + Optional ticket3 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("arg@boo.com", "123-12312", "+32421255", new HashSet<>(Arrays.asList(6, 8, 13, 19)))); assertTrue(ticket3.isPresent()); - assertEquals(admin.getAllSubmittedTickets().size(), 3); + assertEquals(lotterySystem.getAllSubmittedTickets().size(), 3); // perform lottery - LotteryNumbers winningNumbers = admin.performLottery(); + LotteryNumbers winningNumbers = lotterySystem.performLottery(); // cheat a bit for testing sake, use winning numbers to submit another ticket - Optional ticket4 = service.submitTicket(LotteryTestUtils.createLotteryTicket("lucky@orb.com", + Optional ticket4 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("lucky@orb.com", "123-12312", "+12421255", winningNumbers.getNumbers())); assertTrue(ticket4.isPresent()); - assertEquals(admin.getAllSubmittedTickets().size(), 4); + assertEquals(lotterySystem.getAllSubmittedTickets().size(), 4); // check winners - Map tickets = admin.getAllSubmittedTickets(); + Map tickets = lotterySystem.getAllSubmittedTickets(); for (LotteryTicketId id: tickets.keySet()) { - LotteryTicketCheckResult checkResult = service.checkTicketForPrize(id, winningNumbers); + LotteryTicketCheckResult checkResult = lotterySystem.checkTicketForPrize(id, winningNumbers); assertTrue(checkResult.getResult() != CheckResult.TICKET_NOT_SUBMITTED); if (checkResult.getResult().equals(CheckResult.WIN_PRIZE)) { assertTrue(checkResult.getPrizeAmount() > 0); @@ -109,7 +101,7 @@ public class LotteryTest { } // check another ticket that has not been submitted - LotteryTicketCheckResult checkResult = service.checkTicketForPrize(new LotteryTicketId(), winningNumbers); + LotteryTicketCheckResult checkResult = lotterySystem.checkTicketForPrize(new LotteryTicketId(), winningNumbers); assertTrue(checkResult.getResult() == CheckResult.TICKET_NOT_SUBMITTED); assertEquals(checkResult.getPrizeAmount(), 0); } From 3cb872807eee1173ef4724f51aab10a12e963dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 4 Sep 2016 10:33:26 +0300 Subject: [PATCH 044/492] Hexagonal pattern: remove unnecessary repository usage from a unit test --- .../java/com/iluwatar/hexagonal/domain/LotteryTest.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java index 59c8c1930..3e114ddc4 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java @@ -49,20 +49,16 @@ import com.iluwatar.hexagonal.test.LotteryTestUtils; public class LotteryTest { private final LotterySystem lotterySystem = new LotterySystemImpl(); - private final LotteryTicketRepository repository = new LotteryTicketInMemoryRepository(); private final WireTransfers wireTransfers = new WireTransfersImpl(); @Before public void clear() { - repository.deleteAll(); + // add funds to the test player's bank account + wireTransfers.setFunds("123-12312", 100); } @Test public void testLottery() { - - // setup bank account with funds - wireTransfers.setFunds("123-12312", 100); - // admin resets the lottery lotterySystem.resetLottery(); assertEquals(lotterySystem.getAllSubmittedTickets().size(), 0); From 4493341ba6e122c605b05e0d1249631b8bada248 Mon Sep 17 00:00:00 2001 From: Markus Moser Date: Sun, 4 Sep 2016 11:00:24 +0200 Subject: [PATCH 045/492] add documentation to 'use latest java 8' change --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 19d4614f4..613f737d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ after_success: - mvn clean test jacoco:report coveralls:report - bash update-ghpages.sh +# use latest java version available instead of travis default addons: apt: packages: From 22821ba8cc677172e802315a4c85592123286d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 6 Sep 2016 21:35:36 +0300 Subject: [PATCH 046/492] Move Guice to parent pom dependency management section --- dependency-injection/pom.xml | 9 +- pom.xml | 819 ++++++++++++++++++----------------- 2 files changed, 416 insertions(+), 412 deletions(-) diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index 3472da240..88ccdd2d4 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -43,10 +43,9 @@ mockito-core test - - com.google.inject - guice - 4.0 - + + com.google.inject + guice + diff --git a/pom.xml b/pom.xml index 302346993..023579e97 100644 --- a/pom.xml +++ b/pom.xml @@ -17,413 +17,418 @@ 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. ---> - 4.0.0 - - com.iluwatar - java-design-patterns - 1.13.0-SNAPSHOT - pom - - 2014 - - - UTF-8 - 5.0.1.Final - 4.2.4.RELEASE - 1.3.3.RELEASE - 1.9.2.RELEASE - 1.4.190 - 4.12 - 3.0 - 4.0.0 - 0.7.2.201409121644 - 1.4 - 2.16.1 - 1.2.17 - 19.0 - 1.15.1 - 1.10.19 - 4.12.1 +--> + + 4.0.0 + com.iluwatar + java-design-patterns + 1.13.0-SNAPSHOT + pom + 2014 + + UTF-8 + 5.0.1.Final + 4.2.4.RELEASE + 1.3.3.RELEASE + 1.9.2.RELEASE + 1.4.190 + 4.12 + 3.0 + 4.0.0 + 0.7.2.201409121644 + 1.4 + 2.16.1 + 1.2.17 + 19.0 + 1.15.1 + 1.10.19 + 4.12.1 4.5.2 2.22 1.4.1 - - - abstract-factory - builder - factory-method - prototype - singleton - adapter - bridge - composite - dao - data-mapper - decorator - facade - flyweight - proxy - chain - command - interpreter - iterator - mediator - memento - model-view-presenter - observer - state - strategy - template-method - visitor - double-checked-locking - servant - service-locator - null-object - event-aggregator - callback - execute-around - property - intercepting-filter - producer-consumer - poison-pill - reader-writer-lock - lazy-loading - service-layer - specification - tolerant-reader - model-view-controller - flux - double-dispatch - multiton - resource-acquisition-is-initialization - thread-pool - twin - private-class-data - object-pool - dependency-injection - naked-objects - front-controller - repository - async-method-invocation - monostate - step-builder - business-delegate - half-sync-half-async - layers - message-channel - fluentinterface - reactor - caching - publish-subscribe - delegation - event-driven-architecture - api-gateway - factory-kit - feature-toggle - value-object - monad - mute-idiom - mutex - semaphore - hexagonal - abstract-document - aggregator-microservices - promise + 4.0 + + + abstract-factory + builder + factory-method + prototype + singleton + adapter + bridge + composite + dao + data-mapper + decorator + facade + flyweight + proxy + chain + command + interpreter + iterator + mediator + memento + model-view-presenter + observer + state + strategy + template-method + visitor + double-checked-locking + servant + service-locator + null-object + event-aggregator + callback + execute-around + property + intercepting-filter + producer-consumer + poison-pill + reader-writer-lock + lazy-loading + service-layer + specification + tolerant-reader + model-view-controller + flux + double-dispatch + multiton + resource-acquisition-is-initialization + thread-pool + twin + private-class-data + object-pool + dependency-injection + naked-objects + front-controller + repository + async-method-invocation + monostate + step-builder + business-delegate + half-sync-half-async + layers + message-channel + fluentinterface + reactor + caching + publish-subscribe + delegation + event-driven-architecture + api-gateway + factory-kit + feature-toggle + value-object + monad + mute-idiom + mutex + semaphore + hexagonal + abstract-document + aggregator-microservices + promise page-object - + - - - - org.hibernate - hibernate-core - ${hibernate.version} - - - org.hibernate - hibernate-entitymanager - ${hibernate.version} - - - org.springframework - spring-test - ${spring.version} - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - org.springframework.data - spring-data-jpa - ${spring-data.version} - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework.boot - spring-boot-starter-web - ${spring-boot.version} - - - org.apache.httpcomponents - httpclient - ${apache-httpcomponents.version} - - - com.h2database - h2 - ${h2.version} - - - commons-dbcp - commons-dbcp - ${commons-dbcp.version} - - - org.apache.camel - camel-core - ${camel.version} - - - org.apache.camel - camel-stream - ${camel.version} - - - junit - junit - ${junit.version} - test - - - org.mockito - mockito-core - ${mockito.version} - test - - - log4j - log4j - ${log4j.version} - - - com.google.guava - guava - ${guava.version} - - - com.github.stefanbirkner - system-rules - ${systemrules.version} - test - - - de.bechte.junit - junit-hierarchicalcontextrunner - ${hierarchical-junit-runner-version} - test - - - net.sourceforge.htmlunit - htmlunit - ${htmlunit.version} - test - - - + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate + hibernate-entitymanager + ${hibernate.version} + + + org.springframework + spring-test + ${spring.version} + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + org.springframework.data + spring-data-jpa + ${spring-data.version} + + + org.springframework + spring-webmvc + ${spring.version} + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + + org.apache.httpcomponents + httpclient + ${apache-httpcomponents.version} + + + com.h2database + h2 + ${h2.version} + + + commons-dbcp + commons-dbcp + ${commons-dbcp.version} + + + org.apache.camel + camel-core + ${camel.version} + + + org.apache.camel + camel-stream + ${camel.version} + + + junit + junit + ${junit.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + log4j + log4j + ${log4j.version} + + + com.google.guava + guava + ${guava.version} + + + com.github.stefanbirkner + system-rules + ${systemrules.version} + test + + + de.bechte.junit + junit-hierarchicalcontextrunner + ${hierarchical-junit-runner-version} + test + + + net.sourceforge.htmlunit + htmlunit + ${htmlunit.version} + test + + + com.google.inject + guice + ${guice.version} + + + - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.jacoco - - jacoco-maven-plugin - - - [0.6.2,) - - - prepare-agent - - - - - - - - - - - - + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.jacoco + + jacoco-maven-plugin + + + [0.6.2,) + + + prepare-agent + + + + + + + + + + + + - - - - org.apache.maven.plugins - maven-compiler-plugin - ${compiler.version} - - 1.8 - 1.8 - - - - org.eluder.coveralls - coveralls-maven-plugin - ${coveralls.version} - - jb6wYzxkVvjolD6qOWpzWdcWBzYk2fAmF - - - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - - - - domainapp/dom/modules/simple/QSimpleObject.class - **com.steadystate* - - - - - prepare-agent - - prepare-agent - - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - 2.17 - - - validate - - check - - validate - - checkstyle.xml - checkstyle-suppressions.xml - UTF-8 - true - true - true - - - - - - - org.jacoco - jacoco-maven-plugin - 0.7.5.201505241946 - - - - prepare-agent - - - - report - prepare-package - - report - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.18.1 - - - org.apache.maven.surefire - surefire-junit47 - 2.18.1 - - - - -Xmx1024M ${argLine} - - + + - org.apache.maven.plugins - maven-pmd-plugin - 3.6 - - true - 5 - true - - - - - check - - - exclude-pmd.properties - - - + org.apache.maven.plugins + maven-compiler-plugin + ${compiler.version} + + 1.8 + 1.8 + + + + org.eluder.coveralls + coveralls-maven-plugin + ${coveralls.version} + + jb6wYzxkVvjolD6qOWpzWdcWBzYk2fAmF + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + + domainapp/dom/modules/simple/QSimpleObject.class + **com.steadystate* + + + + + prepare-agent + + prepare-agent + + + - - com.mycila - license-maven-plugin - 2.11 - -
    com/mycila/maven/plugin/license/templates/MIT.txt
    - - Ilkka Seppälä - - true -
    - - - install-format - install - - format - - - -
    + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.17 + + + validate + + check + + validate + + checkstyle.xml + checkstyle-suppressions.xml + UTF-8 + true + true + true + + + + + + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + + + prepare-agent + + + + report + prepare-package + + report + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + org.apache.maven.surefire + surefire-junit47 + 2.18.1 + + + + -Xmx1024M ${argLine} + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.6 + + true + 5 + true + + + + + check + + + exclude-pmd.properties + + + + + + + com.mycila + license-maven-plugin + 2.11 + +
    com/mycila/maven/plugin/license/templates/MIT.txt
    + + Ilkka Seppälä + + true +
    + + + install-format + install + + format + + + +
    com.github.markusmo3.urm @@ -448,17 +453,17 @@ -
    -
    + +
    - - - - org.apache.maven.plugins - maven-pmd-plugin - 3.6 - - - + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.6 + + +
    From 348e577e8ed80b3cf7642b40d5b5378e6965fea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 6 Sep 2016 21:39:08 +0300 Subject: [PATCH 047/492] Hexagonal pattern: Add Guice dependency --- hexagonal/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index e9e2a502d..a73fea48d 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -39,5 +39,9 @@ junit test + + com.google.inject + guice + From 1b10ddbb73ff167e6a411b73442cfeb4b8ed754d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 6 Sep 2016 22:39:39 +0300 Subject: [PATCH 048/492] Hexagonal pattern: Use Guice dependency injection --- .../main/java/com/iluwatar/hexagonal/App.java | 11 ++-- .../com/iluwatar/hexagonal/LotteryModule.java | 52 +++++++++++++++++++ .../LotteryAdministrationImpl.java | 7 +-- .../hexagonal/domain/LotterySystemImpl.java | 27 ++++++---- .../hexagonal/service/LotteryServiceImpl.java | 7 +-- .../hexagonal/LotteryTestingModule.java | 52 +++++++++++++++++++ .../hexagonal/domain/LotteryTest.java | 21 ++++++-- 7 files changed, 152 insertions(+), 25 deletions(-) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java create mode 100644 hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java index 92ebf3572..8f99fb15a 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java @@ -26,15 +26,15 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; +import com.google.inject.Guice; +import com.google.inject.Injector; import com.iluwatar.hexagonal.administration.LotteryAdministration; -import com.iluwatar.hexagonal.administration.LotteryAdministrationImpl; import com.iluwatar.hexagonal.banking.WireTransfersImpl; import com.iluwatar.hexagonal.domain.LotteryConstants; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.PlayerDetails; import com.iluwatar.hexagonal.service.LotteryService; -import com.iluwatar.hexagonal.service.LotteryServiceImpl; /** * @@ -124,12 +124,15 @@ public class App { * Program entry point */ public static void main(String[] args) { + + Injector injector = Guice.createInjector(new LotteryModule()); + // start new lottery round - LotteryAdministration administartion = new LotteryAdministrationImpl(); + LotteryAdministration administartion = injector.getInstance(LotteryAdministration.class); administartion.resetLottery(); // submit some lottery tickets - LotteryServiceImpl service = new LotteryServiceImpl(); + LotteryService service = injector.getInstance(LotteryService.class); submitTickets(service, 20); // perform lottery diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java new file mode 100644 index 000000000..b51bff9f4 --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java @@ -0,0 +1,52 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal; + +import com.google.inject.AbstractModule; +import com.iluwatar.hexagonal.administration.LotteryAdministration; +import com.iluwatar.hexagonal.administration.LotteryAdministrationImpl; +import com.iluwatar.hexagonal.banking.WireTransfers; +import com.iluwatar.hexagonal.banking.WireTransfersImpl; +import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; +import com.iluwatar.hexagonal.database.LotteryTicketRepository; +import com.iluwatar.hexagonal.domain.LotterySystem; +import com.iluwatar.hexagonal.domain.LotterySystemImpl; +import com.iluwatar.hexagonal.notifications.LotteryNotifications; +import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; +import com.iluwatar.hexagonal.service.LotteryService; +import com.iluwatar.hexagonal.service.LotteryServiceImpl; + +/** + * Guice module for binding production dependencies + */ +public class LotteryModule extends AbstractModule { + @Override + protected void configure() { + bind(LotteryTicketRepository.class).to(LotteryTicketInMemoryRepository.class); + bind(LotterySystem.class).to(LotterySystemImpl.class); + bind(LotteryNotifications.class).to(LotteryNotificationsImpl.class); + bind(WireTransfers.class).to(WireTransfersImpl.class); + bind(LotteryAdministration.class).to(LotteryAdministrationImpl.class); + bind(LotteryService.class).to(LotteryServiceImpl.class); + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java index 2003849c2..bef2f07c3 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministrationImpl.java @@ -22,9 +22,9 @@ */ package com.iluwatar.hexagonal.administration; +import com.google.inject.Inject; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotterySystem; -import com.iluwatar.hexagonal.domain.LotterySystemImpl; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; @@ -39,8 +39,9 @@ public class LotteryAdministrationImpl implements LotteryAdministration { private final LotterySystem lotterySystem; - public LotteryAdministrationImpl() { - lotterySystem = new LotterySystemImpl(); + @Inject + public LotteryAdministrationImpl(LotterySystem lotterySystem) { + this.lotterySystem = lotterySystem; } @Override diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java index a9290520c..e37185143 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java @@ -22,12 +22,10 @@ */ package com.iluwatar.hexagonal.domain; +import com.google.inject.Inject; import com.iluwatar.hexagonal.banking.WireTransfers; -import com.iluwatar.hexagonal.banking.WireTransfersImpl; -import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.notifications.LotteryNotifications; -import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; import java.util.Map; import java.util.Optional; @@ -38,11 +36,18 @@ import java.util.Optional; public class LotterySystemImpl implements LotterySystem { private final LotteryTicketRepository repository; - private final LotteryNotifications notifications = new LotteryNotificationsImpl(); - private final WireTransfers bank = new WireTransfersImpl(); + private final LotteryNotifications notifications; + private final WireTransfers wireTransfers; - public LotterySystemImpl() { - repository = new LotteryTicketInMemoryRepository(); + /** + * Constructor + */ + @Inject + public LotterySystemImpl(LotteryTicketRepository repository, LotteryNotifications notifications, + WireTransfers wireTransfers) { + this.repository = repository; + this.notifications = notifications; + this.wireTransfers = wireTransfers; } @Override @@ -57,8 +62,8 @@ public class LotterySystemImpl implements LotterySystem { for (LotteryTicketId id : tickets.keySet()) { LotteryTicketCheckResult result = checkTicketForPrize(id, numbers); if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { - boolean transferred = bank.transferFunds(LotteryConstants.PRIZE_AMOUNT, LotteryConstants.SERVICE_BANK_ACCOUNT, - tickets.get(id).getPlayerDetails().getBankAccount()); + boolean transferred = wireTransfers.transferFunds(LotteryConstants.PRIZE_AMOUNT, + LotteryConstants.SERVICE_BANK_ACCOUNT, tickets.get(id).getPlayerDetails().getBankAccount()); if (transferred) { notifications.notifyPrize(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); } else { @@ -78,8 +83,8 @@ public class LotterySystemImpl implements LotterySystem { @Override public Optional submitTicket(LotteryTicket ticket) { - boolean result = bank.transferFunds(LotteryConstants.TICKET_PRIZE, ticket.getPlayerDetails().getBankAccount(), - LotteryConstants.SERVICE_BANK_ACCOUNT); + boolean result = wireTransfers.transferFunds(LotteryConstants.TICKET_PRIZE, + ticket.getPlayerDetails().getBankAccount(), LotteryConstants.SERVICE_BANK_ACCOUNT); if (result == false) { notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); return Optional.empty(); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java index 5bce62054..c912bb0b4 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java @@ -22,9 +22,9 @@ */ package com.iluwatar.hexagonal.service; +import com.google.inject.Inject; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotterySystem; -import com.iluwatar.hexagonal.domain.LotterySystemImpl; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; import com.iluwatar.hexagonal.domain.LotteryTicketId; @@ -43,8 +43,9 @@ public class LotteryServiceImpl implements LotteryService { /** * Constructor */ - public LotteryServiceImpl() { - lotterySystem = new LotterySystemImpl(); + @Inject + public LotteryServiceImpl(LotterySystem lotterySystem) { + this.lotterySystem = lotterySystem; } @Override diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java new file mode 100644 index 000000000..5fbeb8240 --- /dev/null +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java @@ -0,0 +1,52 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal; + +import com.google.inject.AbstractModule; +import com.iluwatar.hexagonal.administration.LotteryAdministration; +import com.iluwatar.hexagonal.administration.LotteryAdministrationImpl; +import com.iluwatar.hexagonal.banking.WireTransfers; +import com.iluwatar.hexagonal.banking.WireTransfersImpl; +import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; +import com.iluwatar.hexagonal.database.LotteryTicketRepository; +import com.iluwatar.hexagonal.domain.LotterySystem; +import com.iluwatar.hexagonal.domain.LotterySystemImpl; +import com.iluwatar.hexagonal.notifications.LotteryNotifications; +import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; +import com.iluwatar.hexagonal.service.LotteryService; +import com.iluwatar.hexagonal.service.LotteryServiceImpl; + +/** + * Guice module for testing dependencies + */ +public class LotteryTestingModule extends AbstractModule { + @Override + protected void configure() { + bind(LotteryTicketRepository.class).to(LotteryTicketInMemoryRepository.class); + bind(LotterySystem.class).to(LotterySystemImpl.class); + bind(LotteryNotifications.class).to(LotteryNotificationsImpl.class); + bind(WireTransfers.class).to(WireTransfersImpl.class); + bind(LotteryAdministration.class).to(LotteryAdministrationImpl.class); + bind(LotteryService.class).to(LotteryServiceImpl.class); + } +} diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java index 3e114ddc4..331cc0d66 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java @@ -30,6 +30,11 @@ import java.util.HashSet; import java.util.Map; import java.util.Optional; +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.iluwatar.hexagonal.LotteryModule; +import com.iluwatar.hexagonal.LotteryTestingModule; import com.iluwatar.hexagonal.domain.*; import org.junit.Before; import org.junit.Test; @@ -48,11 +53,19 @@ import com.iluwatar.hexagonal.test.LotteryTestUtils; */ public class LotteryTest { - private final LotterySystem lotterySystem = new LotterySystemImpl(); - private final WireTransfers wireTransfers = new WireTransfersImpl(); - + private Injector injector; + @Inject + private LotterySystem lotterySystem; + @Inject + private WireTransfers wireTransfers; + + public LotteryTest() { + this.injector = Guice.createInjector(new LotteryTestingModule()); + } + @Before - public void clear() { + public void setup() { + injector.injectMembers(this); // add funds to the test player's bank account wireTransfers.setFunds("123-12312", 100); } From 0f2807b9cfd2863d6486e968bd32fca2d99c42d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 9 Sep 2016 21:36:17 +0300 Subject: [PATCH 049/492] Hexagonal pattern: More descriptive class names --- hexagonal/etc/hexagonal.png | Bin 165940 -> 148602 bytes hexagonal/etc/hexagonal.ucls | 357 ++++++++---------- .../main/java/com/iluwatar/hexagonal/App.java | 4 +- .../com/iluwatar/hexagonal/LotteryModule.java | 20 +- ...onImpl.java => ConsoleAdministration.java} | 4 +- ...reTransfersImpl.java => InMemoryBank.java} | 2 +- ...ory.java => InMemoryTicketRepository.java} | 2 +- ...ionsImpl.java => StdOutNotifications.java} | 2 +- ...ryServiceImpl.java => ConsoleService.java} | 4 +- .../hexagonal/LotteryTestingModule.java | 20 +- .../hexagonal/banking/WireTransfersTest.java | 2 +- .../database/LotteryTicketRepositoryTest.java | 6 +- .../hexagonal/domain/LotteryTest.java | 5 - 13 files changed, 188 insertions(+), 240 deletions(-) rename hexagonal/src/main/java/com/iluwatar/hexagonal/administration/{LotteryAdministrationImpl.java => ConsoleAdministration.java} (93%) rename hexagonal/src/main/java/com/iluwatar/hexagonal/banking/{WireTransfersImpl.java => InMemoryBank.java} (97%) rename hexagonal/src/main/java/com/iluwatar/hexagonal/database/{LotteryTicketInMemoryRepository.java => InMemoryTicketRepository.java} (96%) rename hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/{LotteryNotificationsImpl.java => StdOutNotifications.java} (97%) rename hexagonal/src/main/java/com/iluwatar/hexagonal/service/{LotteryServiceImpl.java => ConsoleService.java} (94%) diff --git a/hexagonal/etc/hexagonal.png b/hexagonal/etc/hexagonal.png index 8c03d375f998e2cd843e7a1dbc3726dc3720c8a0..1ad077fd4fd0e9874c2f85f3f488ead2e3fe7ffc 100644 GIT binary patch literal 148602 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�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 A!2kdN literal 165940 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

    A zp6;RS#Qe4lzk-XHq8rQ$`eK!KW~s;glg~Qk{#K>zXg4MF9i@dKU*=SWLbt@^>~t#u+2tK@9=_n4J4XvbI}`{q4lRg3ew4@@;j}NZzll zvEsBV@mWHSJj%~Emv8N;sc{3)3qV_M{sYG(FZl%peW2unXvZUI=1fRPGC;wtM!|oi z4m`hB$o|8Pnm#xnvJ1ZBnCzTWas9SKP-bp)A8_(N$%-j3bjE&(g#b4lY8#Ke5I7%O zq4Pr4N?Y5xPBY}tt&I4-gO7g!`D3Rr=Zf>7OI9iaBH+8g1dy@s0{FVDXlW1y^F#Xt zMf77?1*SvFN{f!OXTthN{!9}bueZA2Nc#Gkb`)p;>1UBe%{98K@j zcc16~h@qpqFgIkIv%w>e451h1Nx30r2POmuY?vp1SgiLl2bCqKtB)l;Nx?~W8rJXS4Sj{d<*rSyNgnc_RIU9d(!e`o_9*!` z)spaG1M=ZEY5=t$R^odtd#nw*4(YtYrG=fb1vyU;=;M?NYnuxfGD zgYwrTLVw$K-=Z7zu=obh!-B+pi$MQHyaKH_t}O0!7LvS98sD7T2{ai0qHAAGrs-;5 zeM3laA7TFaB$_@Mwi84`AzLi;!GR_HBhOU&A=IBphokYRJ?cvmjni zJu9#@H>M`Ndg()=lo`@HGgCX#Zm{9O;f;iZlDO?zHP`ESg|aB2sSv}AyZOi^ddd$_ zS9EV)ZoWv7gRgXmVu?Blb0#$;MEtM)y*jl!n|fh!dhSocIkb6gO$&!y4nA5chbBP7 z!xW8r_qx2jWyMUE_0PTCp0Abgn{cq_a-MzbRBd(?ujGJ2m{RB|0a1)YnH=(L*ulda z>+9U&U1~ZkXaAEMJO6MSa&5$^<3Dn4#^F{ztU*(!SRsRB6=8F?{=5O^pL&4YNcD zk1WRs`8zprM{)VT>~DXC)(`mpZa-GGr8-`e!bj3(bDaJdM3j?Ul8e?~Z-g!B&u7;6 z!G1XK)#BnQucD(@?B|P-X`zoi4x@DF<=fOwsJziNF9Y@Kn=dChi)BqreO_NRKjKK} z;^lkId&j{G$C(mFmGA zRV14jy~NX(7nF;e%wpgzp3Qd{sc%S#6I3tE&4_*vOCzrdA95UJ)?PR53m+P4{Ziq* z1-nsNdQ~U`PQwt!$n{d>L*iGoJ=jLGuei!3GCCOWDRT_QvrSl!YP)YDQk(T(*A-Z2 z&TFWExky=hEE$|@J2Nqlzq35`pqa+3ydiRHwneHvId7es9#K>1z|TLj>D1d>n9s<# zEaFoVyY~j&-oJfdR+9=ZEqAgh){9;Z?hp>U?xmBY>?yXNE4E<=8U{J%9A@e1eIFd1 zQhK@{Lk(?fG@Q#*!|N9sR&Gj0CX}9`rbWOB_ua`vUwnbp)($7q+s{n*W1Z46vH(ogWRsv<8i6RP?A>3Nr0_Xp zkZjEEemYC;6fj~=(PDC{n4Y2aK2z7?qT1Wk~C~Ui+AKUIk2`X}==D28~mcLB}W5;R4(MZI*xTd>g_A|Yy zii%(o=F>I$?(a;QnWb{}!6_e}+JX(YwpK9Fz5>k$&}N!GCt!Nyoi87xnV2pS_&ggA zOYrQe7^QJ1#65BL?6%>JfsbkA@T&LiFFJQ_z4nT?XMivvE-WeZN8oU>yH{8U0!!ys z`X^2I@oYHA7_`0?9(DEjF&=sTPW_WzI!dyO9#rWU4f1i9xUid( zpN_DMwV>-nnrb)JaJ}7uCbe|q>TgD(G5`iE4u7;+=;BO&gyDAW>j7Bp+m@bT8f!}? zHeK&EQY+9M{wMR!3lr+we0 zes5L>>xRf-?TSSPi%O^?P%ijI%qq7?*86QvcGhjgrNg*7)*I4=)Ge#Odj0 zuny38>t+y$2zuf~w^9{XUQAaCDl?zG(*qt17gtYqaw@6-azD{SHft8S!NLCJiD!*@ zzgnmw@RLsS-DY{YrY0*NSnI%j(I!2|Xt|U~cI$H^w%10Ap^fXtjH_+RF^8q`0@oc} z!b_-ArJM8Bm!i;@WssY(vPN7P;Hx9~qm=h z%98u*uL3-ZF4#VLhw*0p^0xBKsL1(v-?X=PmY2KC4OV07@-4fIi+R@8xC#q$LGGE< zE0id1)Se!HCl6C=CK5GQ1kaGDR|#xsWa0~I{{ z1}XU?8AS~sNO@QG;DW-lCr6^Vt&`9x{O|nH3iz#g86t_24G-Oy<*BIIxMPf4GNKa0 z!X7Ld2Uv&Id6sT4X1Qz?@Nd6v8NKDjL%WnhK0F*OQuX{}dPFJ{B2+TXo14Bmkc~G3 z>e?CdkroG^QHbZ+VZ?46ee?HsgAmAP6f11(z`T&vhOqQUT}OIzRMkrw^sMGd5!;M5 zu2b#Ut@PwiB_}fxoeaW(lGxy2+uINr7}|V-1jy*4ppmVpxFc$D^vqO~?ewkX72CRo z_TIwaiSaHd@oo#_ytFhkL(QaK^g2~CqKjKS)R@&u-!{kj+O^>Qhmn*#LDSRINi%}W z^SdE&a6N>?jH|_HnlcEqUaoJL?}gw4t8-RT4bO<9++WT8Fex*oQKwE0X-Kb%z7J(L zIvMhKd_lCcqONXWBx)tsxO1^^hD9QPh?>@UJo%#S%omrPEfJO?cpL1RCa^sg&nO!~ zq)u%T#G9*{hhJ!0ns7B{vM<|UzXA_iO+lS*`H3H)x!7MBe7X9AaV47;{&;=0wPOzm zzSQ2s2GMPThG|o;E+{t77RguXzI|I#Qc`b0K_7{Md3}xlU0_URU)Gs$A5gUoKr})_5KwQ_>Z!0b+ z1ZtZnp*);U+nYyH%IoT`CyIx$>gjk9OI*FmBX;FVw!_AhVxEcW$rFPaGlGX23vwdv z$b?$Y-$QJ%k8}nph9S(K z*FY~~=tENoZNnr?w0C!;f?Cn*iQ<(L!cYH3E6!w|7wKa$mxY^wwRQS(%iTq@45MY9 zoReGTrzTpq(EK$l{;26MMg~qnV&Hog5#QBAY3?|9V)^1G@x}=q1=3@A%$qL-?LDIW z{X;|7n_u18H(se8%4udb@a~!0y9||@4{9trkE4vyy~D8S8hBgOoYVY0w>A_v=W8$h z8U>#sB#aC=nXCdPF0mz^`odFx;j*)VMQD9Cyc*BIv)|9Mnbo5H63?T9r6gt9Pm*%c zG|HJ-Sz8dEC1bRND{eR|%Wz18h(lH-qfguLZF{@2h96qNIVB_d6&l*xT1_4IcFFCz zJi!r0)L$ItI9yY?-nO=I=~noaj`yOX1tlnPKOZT*u^kA;aJTc&N@`zs(P&Y9c=hwV z{SiF;VSXp9r@HvO643yyE&d1^GF8cW4O?0bx^;;w@YWQO@tLnVHw_P+<*@lM*?9+3 z06pndawuVnpEfqCvz1QYi|VErF`uS-Y3U4KtoOw|efo$&l_StQ3*)!784kHGoDZNo zsjjX+vx?uwU-zKG7`CS;x5Q8NZWQ>-g>~ln#1L@8N-MZ-G+v*`v7P?ta6tli)nUdm8-omJ`LQfDBNF`9bH7wx>^}g5<9gqZKQ> zWZKiADZSbx+^Og&Sk~)}G0jq*3t|whuU{U|J944lWqXaXy1M07cmSV{@tr&O{VyF3 zqd|sDmo3VVBHWKjz8tlTjJ)56MmooFSkfp<@)x^e<0i$Q-Nmw?wq zvh2xA8|!s3B>xE}Wr;YY~%|8U6oKaEi3-Nypa=%KR$o7q!& zro*eNR(#fmvGhQ?JHCJXrowxI(?GVrw|5S7ZbH+q^%~|OQw|!62HCv7Yoa6t^z1RG zCU4k^IQa9c?d+u8f7l_|Ik+}BOXS%k1D6RHY%mGXv#Pk$1%j_pD+8gDxP~CF4+at! zD(DC=)|~%2s0^v~1oVNJA@su0wKZ-%y$#qXw$tQvG~uxZJ+HUHUi8^g&&&@SGchH) zy~{u4xRD4YbLxI`J^jl6P!sIM>B)E~AzRzZe9JNg$wKFi!HW{(n#Bc`R{R%hJlBo$ ztHN_%H|o6;w1?4|-}mY*sf-U*V(DME5sk$IE=ys+uYk?gAciQG?a;A#b6Z<-?(9Mj z5tvP(pqj^cijVi2$>dn)-0IvS)}VP!4i9RT+RY8Q^&hnusW(|!o`w#FljB_+=d}ll z9rNo#*^6A9HLnlEJ!K=M@#7Qo0@;989KGuH3qp0w4U zTAS_(AwN09XDA;9O*8NBF9w559JQTv;VnI=lW6!+)sEB@$NnBYM{5dcEB>iZ)N5fJ zm8>_N@ORfXT6hmK?(sYQ&_96jAmpa4YUG#Jqat?S@8k)`eW^QZ42`hsx z%pio@fa|~lGa9reX=wEAV;{~0hsQ2-ZX;cp(0Nj+ps+Bui>_WV32U473tFxjZMxnSYeZOE7v{gdvf>xasL>PeXK3PQ@PdIPxJAq+ zrH=O)>zzS@-+T$nR4nydvV;;>-lY{K+Fckaoa?-5w*L57r_8&zFWb7!N}=Ky8(3&e zeM}SZg<;Hl@f;sM4C~DSN$AT2UdYNbz>^FNTt9vK=uBT-Z?1{V&Bvu(%+%C|?;hTF z_t+kdji;ofK#3^O)6;Ac&OnHjlAgWa>ltMl)r*G%I-YpZ)>?qM8KoS{UBD(Rl-c)!SPLs3|eAi-yFk zCDEhm+4bwwDX5C4Bf$(|=>^UB^jIJfNkgPt>nV(VUT+^CX$Fg);abhsz2_y}Zj^)$ zMUs*!<%#@sqL+^XP+B9UJg;H0olrN2yUht}Zm~K$t`}*LUUIwi(+d4cuqI#A#UOXr zRG28jBbt&Us#^`;UKWj3O8?16g%2huP7)vX>0-0)$_;tMEU+D@V8GU+JJZ)55#9wH z!mH?4(RRy|9xw)aq9sxF`aqHJR2Ms-+nos_K8(#4Q(Yy1N|WB)I=*%%v zPE+v-2XHun7c})SAG9D_Gk-oaqSs$obD}j()dP&*Oy8C@vF^?`5f~m`S3Wr#TMBXJ@g++SC+3MX!wMso&d^CnewN7Xt7Q zbW8_l53-cg5%=}@7|DbZ+BLQ12=Ttuy8djgNEr@Qotlxa0ijs)w}3F`NxW4&pVn#_ zf%1A>7fm(W9Cgxqcy1LY=FY`in*+bSrFVHB7Sy=T87LYz*LNJ`(MG+s6neo%Y61m% z)8kzq>+0^TFFpqZ75qDR86KW)0@9&aARbgUH^U*F_k27$Gu1mb+GGngr~5@J6XQXw zeU8QAIa>;?PXoVZe~ytOK!$6!Tk9Q;D;86ekzkLbxEldafA{XMFt%hSZ#XUlR2mH4 zzoUgZIO_y_q{nWl=+@x|2GvJI!C~{Y>P}H$Wmoopep%A_9ShUUwH!kNqRuq7`tZ|q z+WrC)I~F}j@vjAp8iFzBvY;hc^k5+MOxqW;T?4|vGQ0ushMxw9@#^cLnC2vx12SPs z01dX3mIf~po*0~&mcd^p~j&z99x;sRf$ccS5 zo`P#Iw)bne0M~Hd;L0E`(4B$W0**&y*x`EEe`skG4FYH*fQ1rGO05xbzJyu> zaO1r20S;5OQc?ePfX$!^7f`yZjzK=BTk20*kHb#-IFS#h3GvwnHrf{q5Q*452#4V_&4o{ntSyU{>n-;Pte zF*Ek-UfqCPoE77jTDfdxcl8#rXV2~Wa9@BLfE@{b07!U_#1 zJ{~OdIGp4SNC2QrE*s0&4Sb8$)Fw%oBGF7$5j=Ul-G%;9QCX=*-Ej6-riVF(g^ zeshi+CK@x+&}&@$A4fY(8_;Za_V6GU1K9nC(1}5J{09Mw>{9L?3o3muA61)>${jvg zs4KAu94x#h!^)u{gOmeF1f4<}fvywn88C<}a??pY&y>Pu#zn$9p5lKwJhAKafrgR% z|Lo#!*ymGvIauS_!l!bg=+5{?rJSozAP{=)-7s7XBjlA38A(A+POehCwVcY#JOBjb zcpDH*CzX*!mLrX5<(K21@A>elOh64(${A?sdh-K8lzvZC=M_rf@UxwmT ziY68Npv&V|S`hp0Z$E-eyz5`6!M@@Q9rul}XQ)nT|{=gHnrOZJxqQ$4U?6 zM9*gVU}5*-u+)^N|0CaiJ@9Q3CMH*vpI@)@+M!Q_TCR(uJVLoA?ICxNMIN}_yPLpc zpY07Uks=bWpQXWa_;H+irYMg#$>h_(gAGJ?n)S1lZ{2zgVKgVF$5@NN{DL)Pk$B{z zQFL8QeeRshhuwgWN!A8Qz$laSA&(ck44IvmVlSHS zH?Q)140G=K=Gou39S!0H(Ld0__A4KS{Z-^+puqP1|MS5lu>c}Y({M$djl6!-G>xqR z;1+N4ZcOeh%v-F3Tx6xm_1ZO(2*xz|!m5|U%_e=}aY!c3defE!djp@auS`_>hace0 zSARG)?YK-&#hPGtnn_3$IzIm5gcVZu*dn`Ka!Jm&8wRX>{8C3Yrl^=6-d0>#>rB3~ zUE>KX>eYo?3y|XB(#4^bhRVUBaQ|b~4ku<;r zubnqO%?|9FPx12F8Z7r8R^WR7mF=++iNy?-?nKPF?yO9tP)>#@XSBJVh1oD_S$Bj?J- z48PyerKR>T)P~KJN{u;nPY=1vw!ImgEughp1eKcvFDWZm?*Rusk&Nt&-3rMh~_F_>zor2`uVlpng66~wbE}`N0fEZ5GgtJD(Dz`rHC^3Y zBb4_7`VNne(G@VxCMKK)->U#p-qx0?=i$E0rjDdf z_Xj=B>8IZ)m(Y?cm!wMCQxvjhXQN?T0B#R51{#2TcA^9%v#{{M&NaPyoou6aSz-+r z`}bI{C?y?8loJdm@gC;WPXSg6dbDXNxP99~yPlk=G>GVG0Z>0}1RG%ur$=n;mtY@69JMck%6_XfF}@C6FQ#60C0)C;oZ zP~}j-(8l8IPzAqFI;{XC$+~AWo~R}=AQrl4L8co@htSobZw)3w?N|8vluPDP3P`nF zA(k1-_S++T z4Yj2hdIongv?>V?&_i@HZQnINl9DE-{d_dua5nWCT$0j8Li#R#B~V@&wX=*ZdJwG_yA8lSUVWvTyTOFN{w#H>i__&`Ra`9)+PP#%!SY)l+agb>$^EHHqJO!cFeTz z!x8*tYxB%tyU*Ss#2M32LYcKDe|sNe0HBQv^|x;>g>; z!+!ld#{f*0FldZ^`%=K8)et6@dy}%`;u?8l-slnUd&9On0b}>0VgDRIJ~y74F|G&z zV}JDZ{WW@BY&mTot`6iAeekkx#Qi$jCI+sAe9PxRpyVXzmt zCRdn-3SPvAioXPA;X)f_Mn*<&GESGt%u4#J*Km?rA#mHhV~|I^dwl#no~x=k%ox6Y z{koxj#naQ!|A3g31V{eZPw(LR);%pGGDroIMfJOPU(u6uTixt}$24nd+II~lvO9JF z`<1s5Hj^DPvBKV`S#`sC?JZ#5EsWiT0WFGDj+2>CY^Cg=k0af=H)93+2OZD-FG)Q+ z#T)}|o!e3rQq>EWUodNztbHL9C&0x?!TIreRoU{M$BXR4QGkt%{Y&_Fk0F!=RWn%b z#c&lDCyC{!$7+Jdf)Vg0V=_3`0>KgPeIDnwmz$d#AhX7QT;JT^T%~HH8p$+ zZk<1_!vt(7jn@6+`sC!~?#=uBg_8o@`q$sZQI&@^gCWkU4kvM>Q810+>wk2_kg^*N z4G$~-as4pmZFh1UvHKnuzkc-17d4oI4zp8&C=cSuQ~$I$BiPX=Sy@?&G&s?8FMn)w zF4)bMuv&jy_rRyHfI;eiT!%JZvnwlke_RjaG{eWm#r$y{9*Bxr>*4OIz%+=jH+rv5 zxyWuVfL4wkyDDNotxA2*jX!Q)?;~3I$&)94T)%YgoYva>@SoSOT(N^Dmw#TTq0xs; z{Kxf5n7Z5$dG*ihZ{H5Uxb#1+C&EU&Bo&$c$HN{YWxL|KUG&GpV$a-gZSd|E{PD2& zh#YWesKs~qk49rYGk>!s$fQ?dRxi$oL0jK_FUqyQokH|KD4`g6*rxZCdA~0=7P%86 z`oH<0va)hhe}B&P2L+%QujyzQuI)T8vTWM(+T{nW$+n00>CIVY8^iXyP3(gm5{3Qu z>V`r(dbO4*%4xnDmyiMegw7E=loaN*!~8+~>iOj7L0W8`;AfVqfOjN$r!k|C{ z3wznC^4m^UdPygb1TjAJGV#IEgwQ>lxLtPEQF#s|so)A%*SQN{cQ9%2DtDo>v@4t2 zI6#ZB)n3}i*>#Nya1t1Q;Ek_7yOBtgbG0^gF9!f=4unf=Dq9np{n!kHv`fy_%0!$9 z7Y^2k!JpnL*wo8k|_o^3%Y!4 zYLvaXHDgp@W0KK(tzST;3lS@F*uVq+po;=a#W+B7B&^V1IQ3v@Fx`U(&d$yewlgki zuY>50|F$I3fiwt46}D;sQA1cyUsS=<^zi zR1)Xk_XGlxf8mxT*TWJN@G#B!bO_>nZBRD@Z#6#-$zoRzt}EaeOKNYq&Ro6_bYN0jKQSt8-*|sL}9V6rGgLDIk zX_(MTvbjy2)I|Y3&zvER+1B_C|VmA@ASpe*le}9kv(Fb4p1rzy%H$Ez1XPC`-HF9EONzCPXP<;8I0%MHZ z@3%yEN154l!>ECJnJmw=2F<{f{Crr_+&Qjy@DXFoxj#NFy8CHK%l%q;rJ?47Tl*7N zhF$#6@07%a2=@2>bqXkr zSc2wiptKu~RVuMp0JalopzC3Rl zlw7_-5*OBwX5UYn4er1rEtGpc;&Gm}S;|z_PDqaN%-~cMs%pNJDJrDYGO~!9+d1gY zX)~yx*_sCOfZgb$bS-EaT|k}*0PEu7B(&2DiysE`wA1CS+f7YPJp%$mE9Ru(`{KVx; zmlXIT0omf6zq#bP!&3(OJhOhX`Q{XbjFYEMGS%56<%YAM9)n1Du`^aA7>=~)21wAb z`YBdtsK7{++Sy4YhEAh^%R^7rD3=0BBq{^kL2_y)6pw%n1+KQ`{d5;Xd-h8`D6 zK_hU1#hm&W53JIslAn%)PA+=1bn($Xv!Yq#G->DRqK~FWF*~w6&NfjvPU`vJq7<~< zr-Fz;3_d%Rr%H{%_(88HBxr!E#CJAFDm*A1XxOqxKuDdWUiby9QL`Oj|CnMRk-_pw zytphK1Y!ShMrq&Xrw0TeL#Bi}gq3N=lut0og$MRt?@IxrG0VaCZ<}B1N@RC!K?$3V zE~B}Xlgcv8Y%~JO2w?2N;o&$cDKW9usBL-39r%EM*X5B{1=e#Flv!A&-r~l)*I)}2 zp>7Khk-5)f6g+%WpIek&4W;sLhM%aV3P{!)n}qxX-g$sB$=b%n{}L;L5~RdUNCt>X5X5w&Uz-=tIHYtX0E_4Qm+4?b`DEgzzE)U zA3Z38P}De*3ZOLf`O+ys>*osOyzR)`!o_t(WFpfUs;&~U$cd{E7$=Z3pMdqh$SqG+1tT8d_?3dD1~{2`nfeJ| zkrdbhujqG{GR%@0P#uP~>_#ytc5okQ5Mhb)E;b5Slw7poEMTGLlJ;%ygrc}Xv2pC7 zh^GI^S+b}i$s_n`&nNdEH6Tp?vPIwRy4kSbmrP@=Hd2$n$c}o(P`~TpKC_1sPD~%6 z3xbO(Gr#7@r^Xb}llQys_@YZT=l|ZST!JaIcVf`1P|1S213S6-HNZFuv*O~8Ld1Qp z{4%5q^Y~b6rq?hcrh$}?;&Xx*1agif0V?inF%1=rjwijIUSdEBI*CsZ%bMfGI@*#f z%|Ty~m|+FL$tO7{#RfqRuZS$Pp12EqYMTY9dQ;H)Hnv-VwAJ@Li|T<(%Tn}%wPg7z zBC9f1o~t^do*F{=0QuC(UVO6DWmBc}^IB>@)AkjVzTxX4x^8_?dV(fsN$9nxzstty zQX+)z_F99h12C)5T`Iq7Fl7DVAjmyH5D@}~if$G3^b?ttlv9l_bJ(6ybW4$9aePpU zE=_EJUR4dL5I+SH-V_DLo7{kk1ORUZ57rTVy%+X;2H-nTI03MiQkJeapK}4ll~?nR zNE{$^DuIwgH3>we*HoYyvuIwdW2pKq6mGT+t3!e2hLzEsFsf$ zn_3(2@Y-2SRM~&Xj!2o;fB4|hbEpTpb)+d&e>n{YUN!(C4(?4Jj1QpGP!#%{5$<&9yf(EWjZ8Ew%n;?=IKL8OlAGm_|iFzV`K5`O( zeG1Bxvnf0GIE4?Eo~8^ZW!$O3WS{zY@`x$`K)(j)4^icA@5}@!vMt=&-Cpu}xmTAq zBuccnuF&4$`8}=$UHZ*`4nmY2fb&z50=SYa77_e8(gIwGM&b8t=0EzNJPfJ^1h&tS zX#nbU)xpWGQJ|)}@`2DzTFpXC7eU!m!mZP?K?o%C=fvOQ5s0Untk&v`p*zMG0Li@^ z+4(gSiJ>wjEa0TFeSIoDG_Ay90>7j#yfvOsLA5e9!F>B(@TMc+r2vXj@^)~Zi*bee z8<6?kl=AUy1IiU^ag|xHVlkLJ3k~_$>5H%yIItg?<{%Ul&x}BD(HSa%RMkb(4(si9y)gkB+XgKR5y0_mQEe3kCFH0|9rjR@jqH|DmLY70cv9y3kKmarD ztLoIPL7)9npwNe++pO_S6hsi(P;G%ge)!PPe(-?R8t`Po>Jj`=v`2w#fBKZ14Fdk< z0}md!UVR&RHOfEIdzqaMA*Ki_M$kwE`Q8d)iF?>C)}5$E9s3zeXVU(Z<_3x=!?1XZ zwiHF3fmoj)Y+0fgiIfXKk(ki1Lb?m@UE%#hxK=w38UO@xv#T#JqY^SLs3djwI1DWn zBeMypDDQ6Cts7+sVTowX9fzIIK5{x_ofeRPK*<-HFHOIdv66x(H)@*(!wo1g{ba{n zFwnukWJw@lV!DvdP&B~Uj>}GrjHZ(l84Zm#>}GwhVe+~Hl8~@cDuhMQ(d~03fwZ>E zT={_T22cj^sd;^&=Z}KkK*&a6D5rUu_NZ`WJnRVBpUga+4`%S;k^PW4N|chG=F$hw z95V~W^ZEH)qpq!&FJ5#4qm8+&^BCJcSX>tAw6pad%pg7)@pBMWbwOOZHI_JOIg$$k z9FRPGf)&&uffD2-^=Dx(uJnOpaL(v^$R}NVxO%Teqrb6j6M4Zx6FJuwg5klhhsjKacxp z$v^bJ?*4Gq2TCBp%i>cyu|ly4X*Vd7puC@Dd>l%10L;)~KNqvpnk?Y8_aO6rPX+m( zX6f-S&W>I&l&5-9?f*dBE-l*`4u`b;>`%EQB}yn2bQHPJ2hK?6PF?6|T-;4BpTs}1 zGa!Me<{;qR50!&t#EpfvoXWYYc63-w^kHZF##~t5UWxv@HyMN@~nAu(l`q0BP-6NLiGTI$ozn_z`p8+a#FV)2K&Cs>#5Se zyCM`c0Y_1)2b5)DK0US%I7rIzJpEAB~90@HYYa zZ((*6%jAO+Q~?>z{MjD#pil`2A!wUMv7;@ho-C|Q$OsAftjDF51AC8&+csB!W$Wo1 zLRe+->58k}I?tY-*0)kCqX5r;s_kzex^;Nn88Gc|oIpov^by?zh3s1$*?J~+(um(3 zc9oU#Toj-4v9eLDa1W;4sFjvT1vNx;M~1HZ(PP!XGO-T!_J@bsAV>i@=y`A87E4yO z%D&WzZf!VLkC%HDj<+VKK`m8J$mGmSXjDca)UdbZObwK!qB0UA4J|;lwbJi;L3?9; zq7LH>uuv%!jFwp0LRmEg913M*P{lxcYp-N7l+thDS=Z-r+kj=r!N?*FEaur_3vMHk z7$}nmxO118wKr@~ah0C<<53_KokZtjLN--(lp%RFHC(HY5P-^Io0;ima3!%mAF;_= z5nb(g8{j>_UxxouT4OJ5Gy0uxQ!tGFh2HETt&T^J@_b2rv+8s z(ZQUh=TZF*f>OgahoKK4cqaEvu+?<_PW+qC6$))6A{e2Cd?(;%{F=5ars*IRX^Nc* zfRV^!i4!1Z(7E$nEG`|St@REXOEfM%U*rkpOV6&Y5WdvCr}#!WDxi!%q6gL%LcoWQ z6Bttb5dqHS5iL+j&Bwq@Vt$A6Fvdi2~b~$W8acKR2 zKM%fVp8l^wb^n} zVl|rg-jjrpe7tLkz{RCcwt;scud3=EQ%Ohv{W!Xdx>gc(jCl!F@x%25;A7#`m%rid=mCH+A}iJUcS0pw>lTg{XEK=9=SL-N6HeX zDexd?$@je{0|Wc~N~fO3X>VEyiIp9LYF53zv6d00U`C4RH;OhIoiB&TgoF=e>&5g) zU4Ls4n7d3r+}PQnzqB;v`nlrB2<30@rB%BeFDuz-`9j(9qth#zwMG;!`W8Eie+Ayn zY@gzI6e;2)u=1=>$Y@P<}Ja zoA7i-+l@+>sHx;rDJSOIWYnC~%`(_rm6@9xI4^=9!tW|;X_*uL;e*-*TgJQ#`{VVx zvL81}KR_Gj5U*_zU|ji@mI7eS7Sm$ zo4gP|6^v<+Yvb{*2Yr5Yvo4>xJ-fD0ei(m9B8rmM1KI=6e4LsK z4OK^>5{?kMsj3);hNV7uuq7GQ$B?zYvNKWa*w*iCduw_j%nbkLPUFk{Lj|%gU%FGd zqEB6Z^SRs1C+WQ>o!5)HgiBGA+hqj97ER3B?on6f5_-yd@;?WTF*CMjUtjucQIb5? z8p^&9NU|@=ZZI=d(MN?|6@~ub>3u9M#R2lwp<`qk()ADBNevBchKDu#b(`Bu)#89Cn_sE)+x4ctFzuZrAM#OG-^`u;QYoUxHUySR)~(W?;4S z&CBz+6~J=p&~)cQ=&dLg)YIlH%MpaAsCjNX;V=~DFV!_jnOFvu?X7v|i4qPfFB2^T zgX>y@2RvRi4m8tc#)u{MJn-=$$vk%t|903nT86@c2w|hl!<@)lsdQ&Ep3d8X<`RXL zP%F_qw#o zIs0w~o1Nv<-JzIDgwfBARnJ|PcTNsIqezX{bPk$#ZgUKedf^QHPn5cz5>YUwoj{~m zVHfQ3FAEmap71bk%K#y+$e)C_hVZaxRzP>`9`l{KN*q%1-yFAbZ?JopXlEoOKbk^ z((y+}=b!0~1foWQQMG5ZDsOO&(IEl9bE>VZoEVAXhjxjs8yf_qoQ(Rt1=PvOSryMH z#=>v2vneG?`QRNn9rWVLS#Iv60*6GWY=@;yFy^zf$7{TvPCX@x*Evp&G&atzvDW+W zSPi37pr&~B|J!VvqLkv8J2NUjCmlNUXY!;+Q>L>5&jkSH*OZT6zPMOE7SO(SJ$%`c zGao*@FwMAdneFfa-RMie91Zu~$yVU0C?S)=ryf@d|NiOK;y>2i>kc{H4)XO~KIQ+N zS##I&$JuZF>!rI6OZ0tu{_bhM_jXpeSH_*Ys3Un|;cCBC!rJELnRRtp z*0Y0y)3+{PyYS$v=g(_DFFX2E8LjXRNpf8&?rmOnc3#SjeF1E9=gkky4NG2Zs-?AI z-MS^VXW99mZC##ww5#ROqte_umo*#?!na|w^e-kxtb43*t*r@b0Oi-KY!Vxpr zN(C#IH6A-d(P~^l?VvnSpnrUGVDqgDoR4%(iKe1){dQqGnvweTvuF90zWh}ERc_@m zx9pIRgxFZms9Sexe;3KzI(2%xZk){eeN0~qy3wjrcNy(_yHY!QcrrqJMRRR~fLYt| z;HPWsKNqdf|1WLsx1&__)k0vwfZ~H!8s&W*D~sRD z%)E8qzPyQzk6#&cF2m>K*;uV+>vBJ>;Za%u{>gCPl&ds667#W+-&)3(}Hab^!R=H%^e+rYs>Prt@M*#1CRF4kC?IlZP9Z7_kCSlQyjg$&t8w0&-iN^782Q5 z^#U!*CajJqe7f;0=h4jf*Tw!uwE_#rx79k+)&lF|Qx;}sTYzQ5nKQ2U?#T%XDlg$_ zYpnjZM@_!=+f94mFv-5c$3~LdCAF<|l3r`->U#LhN!Weo>T37enmupw4~S{+io$B& z#?!YtEuUH*<9e(gnmNVUGV^}&#+vmew}l84$p|)_>=# z%gCaSGvXdx9{o`&D9Rz z-`gR|n3051g{aBL$OrCFcwbQ#7g<&pxs6AuOb2Sw>t+)}iyQhTS0>DxcjHo!a=q`e zsYU-jpZ{-K@}eR8`YB*>(bLZ#-YNR}wf59`&z@!JueU2&QIln|Ea%3DCLZAM#mY0K zqT08@UVIVotH+F>K&`6ln@(Dbzt=c_+H#gEvt`W}#jw10m;U?-ku))h`1@y1{=F?F zRqMXhqleAPBV9rI)AHWTvOT$>b|H_I>XEFREpD!?*RD=o6EQI$X3x6I&Zg)|@@vGz zMKb7uNv@~XqP3(uA|@8CMhhsVuqAi2(26Z=4Sg)ey(n*(ZT0(qB*XvL@LmG24$n}4 nubE?DSO9EB!|HX0hPM9 - - + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + - + - - + - - + - - + - - - - - - - - - + - + - - - - - - - - - - - - - - - - + - - + - - + - - - - - - - - - + @@ -146,174 +145,130 @@ - + - - - - - - - - - + - - - - - - - - - + - + + + + + + + + + - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + + + + + - - - - - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + accounts = new HashMap<>(); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/LotteryTicketInMemoryRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java similarity index 96% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/database/LotteryTicketInMemoryRepository.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java index fe17d8cdf..0d510b411 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/LotteryTicketInMemoryRepository.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java @@ -34,7 +34,7 @@ import com.iluwatar.hexagonal.domain.LotteryTicketId; * Mock database for lottery tickets. * */ -public class LotteryTicketInMemoryRepository implements LotteryTicketRepository { +public class InMemoryTicketRepository implements LotteryTicketRepository { private static Map tickets = new HashMap<>(); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/LotteryNotificationsImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/StdOutNotifications.java similarity index 97% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/LotteryNotificationsImpl.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/StdOutNotifications.java index c59a47970..f6bd3b546 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/LotteryNotificationsImpl.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/StdOutNotifications.java @@ -24,7 +24,7 @@ package com.iluwatar.hexagonal.notifications; import com.iluwatar.hexagonal.domain.PlayerDetails; -public class LotteryNotificationsImpl implements LotteryNotifications { +public class StdOutNotifications implements LotteryNotifications { @Override public void notifyTicketSubmitted(PlayerDetails details) { diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleService.java similarity index 94% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleService.java index c912bb0b4..6804f21c5 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryServiceImpl.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleService.java @@ -36,7 +36,7 @@ import java.util.Optional; * Implementation for lottery service * */ -public class LotteryServiceImpl implements LotteryService { +public class ConsoleService implements LotteryService { private final LotterySystem lotterySystem; @@ -44,7 +44,7 @@ public class LotteryServiceImpl implements LotteryService { * Constructor */ @Inject - public LotteryServiceImpl(LotterySystem lotterySystem) { + public ConsoleService(LotterySystem lotterySystem) { this.lotterySystem = lotterySystem; } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java index 5fbeb8240..c401467b5 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java @@ -23,18 +23,18 @@ package com.iluwatar.hexagonal; import com.google.inject.AbstractModule; +import com.iluwatar.hexagonal.administration.ConsoleAdministration; import com.iluwatar.hexagonal.administration.LotteryAdministration; -import com.iluwatar.hexagonal.administration.LotteryAdministrationImpl; +import com.iluwatar.hexagonal.banking.InMemoryBank; import com.iluwatar.hexagonal.banking.WireTransfers; -import com.iluwatar.hexagonal.banking.WireTransfersImpl; -import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; +import com.iluwatar.hexagonal.database.InMemoryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.domain.LotterySystem; import com.iluwatar.hexagonal.domain.LotterySystemImpl; import com.iluwatar.hexagonal.notifications.LotteryNotifications; -import com.iluwatar.hexagonal.notifications.LotteryNotificationsImpl; +import com.iluwatar.hexagonal.notifications.StdOutNotifications; +import com.iluwatar.hexagonal.service.ConsoleService; import com.iluwatar.hexagonal.service.LotteryService; -import com.iluwatar.hexagonal.service.LotteryServiceImpl; /** * Guice module for testing dependencies @@ -42,11 +42,11 @@ import com.iluwatar.hexagonal.service.LotteryServiceImpl; public class LotteryTestingModule extends AbstractModule { @Override protected void configure() { - bind(LotteryTicketRepository.class).to(LotteryTicketInMemoryRepository.class); + bind(LotteryTicketRepository.class).to(InMemoryTicketRepository.class); bind(LotterySystem.class).to(LotterySystemImpl.class); - bind(LotteryNotifications.class).to(LotteryNotificationsImpl.class); - bind(WireTransfers.class).to(WireTransfersImpl.class); - bind(LotteryAdministration.class).to(LotteryAdministrationImpl.class); - bind(LotteryService.class).to(LotteryServiceImpl.class); + bind(LotteryNotifications.class).to(StdOutNotifications.class); + bind(WireTransfers.class).to(InMemoryBank.class); + bind(LotteryAdministration.class).to(ConsoleAdministration.class); + bind(LotteryService.class).to(ConsoleService.class); } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/WireTransfersTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/WireTransfersTest.java index 0274feca3..25fbf460c 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/WireTransfersTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/WireTransfersTest.java @@ -34,7 +34,7 @@ import org.junit.Test; */ public class WireTransfersTest { - private final WireTransfers bank = new WireTransfersImpl(); + private final WireTransfers bank = new InMemoryBank(); @Test public void testInit() { diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/LotteryTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/LotteryTicketRepositoryTest.java index b20e928c8..31cb8f5f0 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/LotteryTicketRepositoryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/LotteryTicketRepositoryTest.java @@ -30,8 +30,6 @@ import java.util.Optional; import org.junit.Before; import org.junit.Test; -import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.test.LotteryTestUtils; @@ -43,7 +41,7 @@ import com.iluwatar.hexagonal.test.LotteryTestUtils; */ public class LotteryTicketRepositoryTest { - private final LotteryTicketRepository repository = new LotteryTicketInMemoryRepository(); + private final LotteryTicketRepository repository = new InMemoryTicketRepository(); @Before public void clear() { @@ -52,7 +50,7 @@ public class LotteryTicketRepositoryTest { @Test public void testCrudOperations() { - LotteryTicketRepository repository = new LotteryTicketInMemoryRepository(); + LotteryTicketRepository repository = new InMemoryTicketRepository(); assertEquals(repository.findAll().size(), 0); LotteryTicket ticket = LotteryTestUtils.createLotteryTicket(); Optional id = repository.save(ticket); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java index 331cc0d66..732f98305 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java @@ -33,16 +33,11 @@ import java.util.Optional; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; -import com.iluwatar.hexagonal.LotteryModule; import com.iluwatar.hexagonal.LotteryTestingModule; -import com.iluwatar.hexagonal.domain.*; import org.junit.Before; import org.junit.Test; import com.iluwatar.hexagonal.banking.WireTransfers; -import com.iluwatar.hexagonal.banking.WireTransfersImpl; -import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.database.LotteryTicketInMemoryRepository; import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult.CheckResult; import com.iluwatar.hexagonal.test.LotteryTestUtils; From adc6019c7e19a958fb775a073c61214f7ca01351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 10 Sep 2016 07:14:24 +0300 Subject: [PATCH 050/492] Hexagonal pattern: Remove interfaces with only one implementation --- hexagonal/etc/hexagonal.ucls | 6 +- .../com/iluwatar/hexagonal/LotteryModule.java | 8 -- .../administration/ConsoleAdministration.java | 61 ---------- .../administration/LotteryAdministration.java | 26 +++- .../hexagonal/domain/LotterySystem.java | 80 +++++++++++-- .../hexagonal/domain/LotterySystemImpl.java | 112 ------------------ .../hexagonal/service/ConsoleService.java | 60 ---------- .../hexagonal/service/LotteryService.java | 28 +++-- .../hexagonal/LotteryTestingModule.java | 8 -- 9 files changed, 115 insertions(+), 274 deletions(-) delete mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java delete mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java delete mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleService.java diff --git a/hexagonal/etc/hexagonal.ucls b/hexagonal/etc/hexagonal.ucls index 8f4481cbd..f698c0dd2 100644 --- a/hexagonal/etc/hexagonal.ucls +++ b/hexagonal/etc/hexagonal.ucls @@ -22,7 +22,7 @@ - @@ -62,7 +62,7 @@ - @@ -122,7 +122,7 @@ - diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java index 978d7ce9f..992e66357 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java @@ -23,17 +23,12 @@ package com.iluwatar.hexagonal; import com.google.inject.AbstractModule; -import com.iluwatar.hexagonal.administration.LotteryAdministration; -import com.iluwatar.hexagonal.administration.ConsoleAdministration; import com.iluwatar.hexagonal.banking.InMemoryBank; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.database.InMemoryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.domain.LotterySystem; -import com.iluwatar.hexagonal.domain.LotterySystemImpl; import com.iluwatar.hexagonal.notifications.LotteryNotifications; import com.iluwatar.hexagonal.notifications.StdOutNotifications; -import com.iluwatar.hexagonal.service.ConsoleService; import com.iluwatar.hexagonal.service.LotteryService; /** @@ -43,10 +38,7 @@ public class LotteryModule extends AbstractModule { @Override protected void configure() { bind(LotteryTicketRepository.class).to(InMemoryTicketRepository.class); - bind(LotterySystem.class).to(LotterySystemImpl.class); bind(LotteryNotifications.class).to(StdOutNotifications.class); bind(WireTransfers.class).to(InMemoryBank.class); - bind(LotteryAdministration.class).to(ConsoleAdministration.class); - bind(LotteryService.class).to(ConsoleService.class); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java deleted file mode 100644 index 1526fc8d6..000000000 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.hexagonal.administration; - -import com.google.inject.Inject; -import com.iluwatar.hexagonal.domain.LotteryNumbers; -import com.iluwatar.hexagonal.domain.LotterySystem; -import com.iluwatar.hexagonal.domain.LotteryTicket; -import com.iluwatar.hexagonal.domain.LotteryTicketId; - -import java.util.Map; - -/** - * - * Lottery administration implementation - * - */ -public class ConsoleAdministration implements LotteryAdministration { - - private final LotterySystem lotterySystem; - - @Inject - public ConsoleAdministration(LotterySystem lotterySystem) { - this.lotterySystem = lotterySystem; - } - - @Override - public Map getAllSubmittedTickets() { - return lotterySystem.getAllSubmittedTickets(); - } - - @Override - public LotteryNumbers performLottery() { - return lotterySystem.performLottery(); - } - - @Override - public void resetLottery() { - lotterySystem.resetLottery(); - } -} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java index c6c034ac9..a59461a48 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java @@ -22,7 +22,9 @@ */ package com.iluwatar.hexagonal.administration; +import com.google.inject.Inject; import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotterySystem; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; @@ -30,24 +32,36 @@ import java.util.Map; /** * - * Administrator interface for lottery service. + * Lottery administration implementation * */ -public interface LotteryAdministration { +public class LotteryAdministration { + + private final LotterySystem lotterySystem; + + @Inject + public LotteryAdministration(LotterySystem lotterySystem) { + this.lotterySystem = lotterySystem; + } /** * Get all the lottery tickets submitted for lottery */ - Map getAllSubmittedTickets(); + public Map getAllSubmittedTickets() { + return lotterySystem.getAllSubmittedTickets(); + } /** * Draw lottery numbers */ - LotteryNumbers performLottery(); + public LotteryNumbers performLottery() { + return lotterySystem.performLottery(); + } /** * Begin new lottery round */ - void resetLottery(); - + public void resetLottery() { + lotterySystem.resetLottery(); + } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java index 2ee114556..ed58c82db 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java @@ -22,37 +22,101 @@ */ package com.iluwatar.hexagonal.domain; +import com.google.inject.Inject; +import com.iluwatar.hexagonal.banking.WireTransfers; +import com.iluwatar.hexagonal.database.LotteryTicketRepository; +import com.iluwatar.hexagonal.notifications.LotteryNotifications; + import java.util.Map; import java.util.Optional; /** - * Lottery system interface + * Lottery system */ -public interface LotterySystem { +public class LotterySystem { + + private final LotteryTicketRepository repository; + private final LotteryNotifications notifications; + private final WireTransfers wireTransfers; + + /** + * Constructor + */ + @Inject + public LotterySystem(LotteryTicketRepository repository, LotteryNotifications notifications, + WireTransfers wireTransfers) { + this.repository = repository; + this.notifications = notifications; + this.wireTransfers = wireTransfers; + } /** * Get all the lottery tickets submitted for lottery */ - Map getAllSubmittedTickets(); + public Map getAllSubmittedTickets() { + return repository.findAll(); + } /** * Draw lottery numbers */ - LotteryNumbers performLottery(); + public LotteryNumbers performLottery() { + LotteryNumbers numbers = LotteryNumbers.createRandom(); + Map tickets = getAllSubmittedTickets(); + for (LotteryTicketId id : tickets.keySet()) { + LotteryTicketCheckResult result = checkTicketForPrize(id, numbers); + if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { + boolean transferred = wireTransfers.transferFunds(LotteryConstants.PRIZE_AMOUNT, + LotteryConstants.SERVICE_BANK_ACCOUNT, tickets.get(id).getPlayerDetails().getBankAccount()); + if (transferred) { + notifications.notifyPrize(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); + } else { + notifications.notifyPrizeError(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); + } + } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { + notifications.notifyNoWin(tickets.get(id).getPlayerDetails()); + } + } + return numbers; + } /** * Begin new lottery round */ - void resetLottery(); + public void resetLottery() { + repository.deleteAll(); + } /** * Submit lottery ticket to participate in the lottery */ - Optional submitTicket(LotteryTicket ticket); + public Optional submitTicket(LotteryTicket ticket) { + boolean result = wireTransfers.transferFunds(LotteryConstants.TICKET_PRIZE, + ticket.getPlayerDetails().getBankAccount(), LotteryConstants.SERVICE_BANK_ACCOUNT); + if (result == false) { + notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); + return Optional.empty(); + } + Optional optional = repository.save(ticket); + if (optional.isPresent()) { + notifications.notifyTicketSubmitted(ticket.getPlayerDetails()); + } + return optional; + } /** * Check if lottery ticket has won */ - LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers); - + public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { + Optional optional = repository.findById(id); + if (optional.isPresent()) { + if (optional.get().getNumbers().equals(winningNumbers)) { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.WIN_PRIZE, 1000); + } else { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.NO_PRIZE); + } + } else { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.TICKET_NOT_SUBMITTED); + } + } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java deleted file mode 100644 index e37185143..000000000 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystemImpl.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.hexagonal.domain; - -import com.google.inject.Inject; -import com.iluwatar.hexagonal.banking.WireTransfers; -import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.notifications.LotteryNotifications; - -import java.util.Map; -import java.util.Optional; - -/** - * Lottery system implementation - */ -public class LotterySystemImpl implements LotterySystem { - - private final LotteryTicketRepository repository; - private final LotteryNotifications notifications; - private final WireTransfers wireTransfers; - - /** - * Constructor - */ - @Inject - public LotterySystemImpl(LotteryTicketRepository repository, LotteryNotifications notifications, - WireTransfers wireTransfers) { - this.repository = repository; - this.notifications = notifications; - this.wireTransfers = wireTransfers; - } - - @Override - public Map getAllSubmittedTickets() { - return repository.findAll(); - } - - @Override - public LotteryNumbers performLottery() { - LotteryNumbers numbers = LotteryNumbers.createRandom(); - Map tickets = getAllSubmittedTickets(); - for (LotteryTicketId id : tickets.keySet()) { - LotteryTicketCheckResult result = checkTicketForPrize(id, numbers); - if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { - boolean transferred = wireTransfers.transferFunds(LotteryConstants.PRIZE_AMOUNT, - LotteryConstants.SERVICE_BANK_ACCOUNT, tickets.get(id).getPlayerDetails().getBankAccount()); - if (transferred) { - notifications.notifyPrize(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); - } else { - notifications.notifyPrizeError(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); - } - } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { - notifications.notifyNoWin(tickets.get(id).getPlayerDetails()); - } - } - return numbers; - } - - @Override - public void resetLottery() { - repository.deleteAll(); - } - - @Override - public Optional submitTicket(LotteryTicket ticket) { - boolean result = wireTransfers.transferFunds(LotteryConstants.TICKET_PRIZE, - ticket.getPlayerDetails().getBankAccount(), LotteryConstants.SERVICE_BANK_ACCOUNT); - if (result == false) { - notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); - return Optional.empty(); - } - Optional optional = repository.save(ticket); - if (optional.isPresent()) { - notifications.notifyTicketSubmitted(ticket.getPlayerDetails()); - } - return optional; - } - - @Override - public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { - Optional optional = repository.findById(id); - if (optional.isPresent()) { - if (optional.get().getNumbers().equals(winningNumbers)) { - return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.WIN_PRIZE, 1000); - } else { - return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.NO_PRIZE); - } - } else { - return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.TICKET_NOT_SUBMITTED); - } - } -} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleService.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleService.java deleted file mode 100644 index 6804f21c5..000000000 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleService.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.hexagonal.service; - -import com.google.inject.Inject; -import com.iluwatar.hexagonal.domain.LotteryNumbers; -import com.iluwatar.hexagonal.domain.LotterySystem; -import com.iluwatar.hexagonal.domain.LotteryTicket; -import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; -import com.iluwatar.hexagonal.domain.LotteryTicketId; - -import java.util.Optional; - -/** - * - * Implementation for lottery service - * - */ -public class ConsoleService implements LotteryService { - - private final LotterySystem lotterySystem; - - /** - * Constructor - */ - @Inject - public ConsoleService(LotterySystem lotterySystem) { - this.lotterySystem = lotterySystem; - } - - @Override - public Optional submitTicket(LotteryTicket ticket) { - return lotterySystem.submitTicket(ticket); - } - - @Override - public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { - return lotterySystem.checkTicketForPrize(id, winningNumbers); - } -} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java index ef2202968..80d306b04 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java @@ -22,27 +22,39 @@ */ package com.iluwatar.hexagonal.service; -import com.iluwatar.hexagonal.domain.LotteryNumbers; -import com.iluwatar.hexagonal.domain.LotteryTicket; -import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; -import com.iluwatar.hexagonal.domain.LotteryTicketId; +import com.google.inject.Inject; +import com.iluwatar.hexagonal.domain.*; import java.util.Optional; /** * - * Interface for submitting and checking lottery tickets. + * Implementation for lottery service * */ -public interface LotteryService { +public class LotteryService { + + private final LotterySystem lotterySystem; + + /** + * Constructor + */ + @Inject + public LotteryService(LotterySystem lotterySystem) { + this.lotterySystem = lotterySystem; + } /** * Submit lottery ticket to participate in the lottery */ - Optional submitTicket(LotteryTicket ticket); + public Optional submitTicket(LotteryTicket ticket) { + return lotterySystem.submitTicket(ticket); + } /** * Check if lottery ticket has won */ - LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers); + public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { + return lotterySystem.checkTicketForPrize(id, winningNumbers); + } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java index c401467b5..252e3e66d 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java @@ -23,17 +23,12 @@ package com.iluwatar.hexagonal; import com.google.inject.AbstractModule; -import com.iluwatar.hexagonal.administration.ConsoleAdministration; -import com.iluwatar.hexagonal.administration.LotteryAdministration; import com.iluwatar.hexagonal.banking.InMemoryBank; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.database.InMemoryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.domain.LotterySystem; -import com.iluwatar.hexagonal.domain.LotterySystemImpl; import com.iluwatar.hexagonal.notifications.LotteryNotifications; import com.iluwatar.hexagonal.notifications.StdOutNotifications; -import com.iluwatar.hexagonal.service.ConsoleService; import com.iluwatar.hexagonal.service.LotteryService; /** @@ -43,10 +38,7 @@ public class LotteryTestingModule extends AbstractModule { @Override protected void configure() { bind(LotteryTicketRepository.class).to(InMemoryTicketRepository.class); - bind(LotterySystem.class).to(LotterySystemImpl.class); bind(LotteryNotifications.class).to(StdOutNotifications.class); bind(WireTransfers.class).to(InMemoryBank.class); - bind(LotteryAdministration.class).to(ConsoleAdministration.class); - bind(LotteryService.class).to(ConsoleService.class); } } From 121ed3cca896d5870225565e50142c23f2cd4f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 10 Sep 2016 07:56:37 +0300 Subject: [PATCH 051/492] Hexagonal pattern: Move lottery administration and service to the core. Introduce console interfaces for players and administartors. --- hexagonal/etc/hexagonal.ucls | 8 +-- .../main/java/com/iluwatar/hexagonal/App.java | 4 +- .../com/iluwatar/hexagonal/LotteryModule.java | 1 - .../administration/ConsoleAdministration.java | 7 ++ .../administration/LotteryAdministration.java | 67 ------------------- ...System.java => LotteryAdministration.java} | 51 +++----------- .../{service => domain}/LotteryService.java | 33 +++++++-- .../domain/LotteryTicketChecker.java | 33 +++++++++ .../hexagonal/service/ConsoleLottery.java | 7 ++ .../hexagonal/LotteryTestingModule.java | 1 - .../hexagonal/domain/LotteryTest.java | 28 ++++---- 11 files changed, 103 insertions(+), 137 deletions(-) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java delete mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java rename hexagonal/src/main/java/com/iluwatar/hexagonal/domain/{LotterySystem.java => LotteryAdministration.java} (64%) rename hexagonal/src/main/java/com/iluwatar/hexagonal/{service => domain}/LotteryService.java (55%) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java diff --git a/hexagonal/etc/hexagonal.ucls b/hexagonal/etc/hexagonal.ucls index f698c0dd2..0318576c2 100644 --- a/hexagonal/etc/hexagonal.ucls +++ b/hexagonal/etc/hexagonal.ucls @@ -62,7 +62,7 @@ - @@ -102,7 +102,7 @@ - @@ -122,7 +122,7 @@ - @@ -142,7 +142,7 @@ - diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java index a1bb26454..83ae15032 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java @@ -28,13 +28,13 @@ import java.util.Random; import com.google.inject.Guice; import com.google.inject.Injector; -import com.iluwatar.hexagonal.administration.LotteryAdministration; +import com.iluwatar.hexagonal.domain.LotteryAdministration; import com.iluwatar.hexagonal.banking.InMemoryBank; import com.iluwatar.hexagonal.domain.LotteryConstants; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.PlayerDetails; -import com.iluwatar.hexagonal.service.LotteryService; +import com.iluwatar.hexagonal.domain.LotteryService; /** * diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java index 992e66357..dbaf494c2 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java @@ -29,7 +29,6 @@ import com.iluwatar.hexagonal.database.InMemoryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.notifications.LotteryNotifications; import com.iluwatar.hexagonal.notifications.StdOutNotifications; -import com.iluwatar.hexagonal.service.LotteryService; /** * Guice module for binding production dependencies diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java new file mode 100644 index 000000000..5238edd24 --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java @@ -0,0 +1,7 @@ +package com.iluwatar.hexagonal.administration; + +/** + * Console interface for lottery administration + */ +public class ConsoleAdministration { +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java deleted file mode 100644 index a59461a48..000000000 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/LotteryAdministration.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.hexagonal.administration; - -import com.google.inject.Inject; -import com.iluwatar.hexagonal.domain.LotteryNumbers; -import com.iluwatar.hexagonal.domain.LotterySystem; -import com.iluwatar.hexagonal.domain.LotteryTicket; -import com.iluwatar.hexagonal.domain.LotteryTicketId; - -import java.util.Map; - -/** - * - * Lottery administration implementation - * - */ -public class LotteryAdministration { - - private final LotterySystem lotterySystem; - - @Inject - public LotteryAdministration(LotterySystem lotterySystem) { - this.lotterySystem = lotterySystem; - } - - /** - * Get all the lottery tickets submitted for lottery - */ - public Map getAllSubmittedTickets() { - return lotterySystem.getAllSubmittedTickets(); - } - - /** - * Draw lottery numbers - */ - public LotteryNumbers performLottery() { - return lotterySystem.performLottery(); - } - - /** - * Begin new lottery round - */ - public void resetLottery() { - lotterySystem.resetLottery(); - } -} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java similarity index 64% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java index ed58c82db..7117397d3 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotterySystem.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java @@ -28,26 +28,26 @@ import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.notifications.LotteryNotifications; import java.util.Map; -import java.util.Optional; /** - * Lottery system + * + * Lottery administration implementation + * */ -public class LotterySystem { +public class LotteryAdministration { private final LotteryTicketRepository repository; private final LotteryNotifications notifications; private final WireTransfers wireTransfers; + private final LotteryTicketChecker checker; - /** - * Constructor - */ @Inject - public LotterySystem(LotteryTicketRepository repository, LotteryNotifications notifications, - WireTransfers wireTransfers) { + public LotteryAdministration(LotteryTicketRepository repository, LotteryNotifications notifications, + WireTransfers wireTransfers) { this.repository = repository; this.notifications = notifications; this.wireTransfers = wireTransfers; + this.checker = new LotteryTicketChecker(this.repository); } /** @@ -64,7 +64,7 @@ public class LotterySystem { LotteryNumbers numbers = LotteryNumbers.createRandom(); Map tickets = getAllSubmittedTickets(); for (LotteryTicketId id : tickets.keySet()) { - LotteryTicketCheckResult result = checkTicketForPrize(id, numbers); + LotteryTicketCheckResult result = checker.checkTicketForPrize(id, numbers); if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { boolean transferred = wireTransfers.transferFunds(LotteryConstants.PRIZE_AMOUNT, LotteryConstants.SERVICE_BANK_ACCOUNT, tickets.get(id).getPlayerDetails().getBankAccount()); @@ -86,37 +86,4 @@ public class LotterySystem { public void resetLottery() { repository.deleteAll(); } - - /** - * Submit lottery ticket to participate in the lottery - */ - public Optional submitTicket(LotteryTicket ticket) { - boolean result = wireTransfers.transferFunds(LotteryConstants.TICKET_PRIZE, - ticket.getPlayerDetails().getBankAccount(), LotteryConstants.SERVICE_BANK_ACCOUNT); - if (result == false) { - notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); - return Optional.empty(); - } - Optional optional = repository.save(ticket); - if (optional.isPresent()) { - notifications.notifyTicketSubmitted(ticket.getPlayerDetails()); - } - return optional; - } - - /** - * Check if lottery ticket has won - */ - public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { - Optional optional = repository.findById(id); - if (optional.isPresent()) { - if (optional.get().getNumbers().equals(winningNumbers)) { - return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.WIN_PRIZE, 1000); - } else { - return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.NO_PRIZE); - } - } else { - return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.TICKET_NOT_SUBMITTED); - } - } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java similarity index 55% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java index 80d306b04..76cd47d1d 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/LotteryService.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java @@ -20,10 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.hexagonal.service; +package com.iluwatar.hexagonal.domain; import com.google.inject.Inject; -import com.iluwatar.hexagonal.domain.*; +import com.iluwatar.hexagonal.banking.WireTransfers; +import com.iluwatar.hexagonal.database.LotteryTicketRepository; +import com.iluwatar.hexagonal.notifications.LotteryNotifications; import java.util.Optional; @@ -34,27 +36,44 @@ import java.util.Optional; */ public class LotteryService { - private final LotterySystem lotterySystem; + private final LotteryTicketRepository repository; + private final LotteryNotifications notifications; + private final WireTransfers wireTransfers; + private final LotteryTicketChecker checker; /** * Constructor */ @Inject - public LotteryService(LotterySystem lotterySystem) { - this.lotterySystem = lotterySystem; + public LotteryService(LotteryTicketRepository repository, LotteryNotifications notifications, + WireTransfers wireTransfers) { + this.repository = repository; + this.notifications = notifications; + this.wireTransfers = wireTransfers; + this.checker = new LotteryTicketChecker(this.repository); } /** * Submit lottery ticket to participate in the lottery */ public Optional submitTicket(LotteryTicket ticket) { - return lotterySystem.submitTicket(ticket); + boolean result = wireTransfers.transferFunds(LotteryConstants.TICKET_PRIZE, + ticket.getPlayerDetails().getBankAccount(), LotteryConstants.SERVICE_BANK_ACCOUNT); + if (result == false) { + notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); + return Optional.empty(); + } + Optional optional = repository.save(ticket); + if (optional.isPresent()) { + notifications.notifyTicketSubmitted(ticket.getPlayerDetails()); + } + return optional; } /** * Check if lottery ticket has won */ public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { - return lotterySystem.checkTicketForPrize(id, winningNumbers); + return checker.checkTicketForPrize(id, winningNumbers); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java new file mode 100644 index 000000000..10042528b --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java @@ -0,0 +1,33 @@ +package com.iluwatar.hexagonal.domain; + +import com.iluwatar.hexagonal.database.LotteryTicketRepository; + +import java.util.Optional; + +/** + * Lottery ticket checker + */ +public class LotteryTicketChecker { + + private final LotteryTicketRepository repository; + + public LotteryTicketChecker(LotteryTicketRepository repository) { + this.repository = repository; + } + + /** + * Check if lottery ticket has won + */ + public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { + Optional optional = repository.findById(id); + if (optional.isPresent()) { + if (optional.get().getNumbers().equals(winningNumbers)) { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.WIN_PRIZE, 1000); + } else { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.NO_PRIZE); + } + } else { + return new LotteryTicketCheckResult(LotteryTicketCheckResult.CheckResult.TICKET_NOT_SUBMITTED); + } + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java new file mode 100644 index 000000000..e48410982 --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -0,0 +1,7 @@ +package com.iluwatar.hexagonal.service; + +/** + * Console interface for lottery players + */ +public class ConsoleLottery { +} diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java index 252e3e66d..22bfa8f01 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java @@ -29,7 +29,6 @@ import com.iluwatar.hexagonal.database.InMemoryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.notifications.LotteryNotifications; import com.iluwatar.hexagonal.notifications.StdOutNotifications; -import com.iluwatar.hexagonal.service.LotteryService; /** * Guice module for testing dependencies diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java index 732f98305..ed6f8d180 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java @@ -50,7 +50,9 @@ public class LotteryTest { private Injector injector; @Inject - private LotterySystem lotterySystem; + private LotteryAdministration administration; + @Inject + private LotteryService service; @Inject private WireTransfers wireTransfers; @@ -68,34 +70,34 @@ public class LotteryTest { @Test public void testLottery() { // admin resets the lottery - lotterySystem.resetLottery(); - assertEquals(lotterySystem.getAllSubmittedTickets().size(), 0); + administration.resetLottery(); + assertEquals(administration.getAllSubmittedTickets().size(), 0); // players submit the lottery tickets - Optional ticket1 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("cvt@bbb.com", + Optional ticket1 = service.submitTicket(LotteryTestUtils.createLotteryTicket("cvt@bbb.com", "123-12312", "+32425255", new HashSet<>(Arrays.asList(1, 2, 3, 4)))); assertTrue(ticket1.isPresent()); - Optional ticket2 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("ant@bac.com", + Optional ticket2 = service.submitTicket(LotteryTestUtils.createLotteryTicket("ant@bac.com", "123-12312", "+32423455", new HashSet<>(Arrays.asList(11, 12, 13, 14)))); assertTrue(ticket2.isPresent()); - Optional ticket3 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("arg@boo.com", + Optional ticket3 = service.submitTicket(LotteryTestUtils.createLotteryTicket("arg@boo.com", "123-12312", "+32421255", new HashSet<>(Arrays.asList(6, 8, 13, 19)))); assertTrue(ticket3.isPresent()); - assertEquals(lotterySystem.getAllSubmittedTickets().size(), 3); + assertEquals(administration.getAllSubmittedTickets().size(), 3); // perform lottery - LotteryNumbers winningNumbers = lotterySystem.performLottery(); + LotteryNumbers winningNumbers = administration.performLottery(); // cheat a bit for testing sake, use winning numbers to submit another ticket - Optional ticket4 = lotterySystem.submitTicket(LotteryTestUtils.createLotteryTicket("lucky@orb.com", + Optional ticket4 = service.submitTicket(LotteryTestUtils.createLotteryTicket("lucky@orb.com", "123-12312", "+12421255", winningNumbers.getNumbers())); assertTrue(ticket4.isPresent()); - assertEquals(lotterySystem.getAllSubmittedTickets().size(), 4); + assertEquals(administration.getAllSubmittedTickets().size(), 4); // check winners - Map tickets = lotterySystem.getAllSubmittedTickets(); + Map tickets = administration.getAllSubmittedTickets(); for (LotteryTicketId id: tickets.keySet()) { - LotteryTicketCheckResult checkResult = lotterySystem.checkTicketForPrize(id, winningNumbers); + LotteryTicketCheckResult checkResult = service.checkTicketForPrize(id, winningNumbers); assertTrue(checkResult.getResult() != CheckResult.TICKET_NOT_SUBMITTED); if (checkResult.getResult().equals(CheckResult.WIN_PRIZE)) { assertTrue(checkResult.getPrizeAmount() > 0); @@ -105,7 +107,7 @@ public class LotteryTest { } // check another ticket that has not been submitted - LotteryTicketCheckResult checkResult = lotterySystem.checkTicketForPrize(new LotteryTicketId(), winningNumbers); + LotteryTicketCheckResult checkResult = service.checkTicketForPrize(new LotteryTicketId(), winningNumbers); assertTrue(checkResult.getResult() == CheckResult.TICKET_NOT_SUBMITTED); assertEquals(checkResult.getPrizeAmount(), 0); } From e17d72bca81523ae4521cc4b198e72980aad8b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 10 Sep 2016 14:28:05 +0300 Subject: [PATCH 052/492] Hexagonal pattern: Added console interfaces for players and administration. --- .../main/java/com/iluwatar/hexagonal/App.java | 81 +---------- .../administration/ConsoleAdministration.java | 77 +++++++++++ .../domain/LotteryAdministration.java | 3 + .../hexagonal/domain/LotteryNumbers.java | 7 +- .../hexagonal/domain/LotteryTicket.java | 5 + .../domain/LotteryTicketChecker.java | 22 +++ .../hexagonal/domain/LotteryTicketId.java | 9 ++ .../hexagonal/domain/PlayerDetails.java | 7 + .../hexagonal/{ => module}/LotteryModule.java | 2 +- .../module}/LotteryTestingModule.java | 2 +- .../hexagonal/sampledata/SampleData.java | 107 ++++++++++++++ .../hexagonal/service/ConsoleLottery.java | 130 ++++++++++++++++++ .../hexagonal/domain/LotteryTest.java | 2 +- 13 files changed, 374 insertions(+), 80 deletions(-) rename hexagonal/src/main/java/com/iluwatar/hexagonal/{ => module}/LotteryModule.java (97%) rename hexagonal/src/{test/java/com/iluwatar/hexagonal => main/java/com/iluwatar/hexagonal/module}/LotteryTestingModule.java (97%) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java index 83ae15032..a7d31446b 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java @@ -22,19 +22,12 @@ */ package com.iluwatar.hexagonal; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - import com.google.inject.Guice; import com.google.inject.Injector; import com.iluwatar.hexagonal.domain.LotteryAdministration; -import com.iluwatar.hexagonal.banking.InMemoryBank; -import com.iluwatar.hexagonal.domain.LotteryConstants; -import com.iluwatar.hexagonal.domain.LotteryNumbers; -import com.iluwatar.hexagonal.domain.LotteryTicket; -import com.iluwatar.hexagonal.domain.PlayerDetails; import com.iluwatar.hexagonal.domain.LotteryService; +import com.iluwatar.hexagonal.module.LotteryTestingModule; +import com.iluwatar.hexagonal.sampledata.SampleData; /** * @@ -68,64 +61,13 @@ import com.iluwatar.hexagonal.domain.LotteryService; * */ public class App { - - private static final List PLAYERS; - - static { - PLAYERS = new ArrayList<>(); - PLAYERS.add(PlayerDetails.create("john@google.com", "312-342", "+3242434242")); - PLAYERS.add(PlayerDetails.create("mary@google.com", "234-987", "+23452346")); - PLAYERS.add(PlayerDetails.create("steve@google.com", "833-836", "+63457543")); - PLAYERS.add(PlayerDetails.create("wayne@google.com", "319-826", "+24626")); - PLAYERS.add(PlayerDetails.create("johnie@google.com", "983-322", "+3635635")); - PLAYERS.add(PlayerDetails.create("andy@google.com", "934-734", "+0898245")); - PLAYERS.add(PlayerDetails.create("richard@google.com", "536-738", "+09845325")); - PLAYERS.add(PlayerDetails.create("kevin@google.com", "453-936", "+2423532")); - PLAYERS.add(PlayerDetails.create("arnold@google.com", "114-988", "+5646346524")); - PLAYERS.add(PlayerDetails.create("ian@google.com", "663-765", "+928394235")); - PLAYERS.add(PlayerDetails.create("robin@google.com", "334-763", "+35448")); - PLAYERS.add(PlayerDetails.create("ted@google.com", "735-964", "+98752345")); - PLAYERS.add(PlayerDetails.create("larry@google.com", "734-853", "+043842423")); - PLAYERS.add(PlayerDetails.create("calvin@google.com", "334-746", "+73294135")); - PLAYERS.add(PlayerDetails.create("jacob@google.com", "444-766", "+358042354")); - PLAYERS.add(PlayerDetails.create("edwin@google.com", "895-345", "+9752435")); - PLAYERS.add(PlayerDetails.create("mary@google.com", "760-009", "+34203542")); - PLAYERS.add(PlayerDetails.create("lolita@google.com", "425-907", "+9872342")); - PLAYERS.add(PlayerDetails.create("bruno@google.com", "023-638", "+673824122")); - PLAYERS.add(PlayerDetails.create("peter@google.com", "335-886", "+5432503945")); - PLAYERS.add(PlayerDetails.create("warren@google.com", "225-946", "+9872341324")); - PLAYERS.add(PlayerDetails.create("monica@google.com", "265-748", "+134124")); - PLAYERS.add(PlayerDetails.create("ollie@google.com", "190-045", "+34453452")); - PLAYERS.add(PlayerDetails.create("yngwie@google.com", "241-465", "+9897641231")); - PLAYERS.add(PlayerDetails.create("lars@google.com", "746-936", "+42345298345")); - PLAYERS.add(PlayerDetails.create("bobbie@google.com", "946-384", "+79831742")); - PLAYERS.add(PlayerDetails.create("tyron@google.com", "310-992", "+0498837412")); - PLAYERS.add(PlayerDetails.create("tyrell@google.com", "032-045", "+67834134")); - PLAYERS.add(PlayerDetails.create("nadja@google.com", "000-346", "+498723")); - PLAYERS.add(PlayerDetails.create("wendy@google.com", "994-989", "+987324454")); - PLAYERS.add(PlayerDetails.create("luke@google.com", "546-634", "+987642435")); - PLAYERS.add(PlayerDetails.create("bjorn@google.com", "342-874", "+7834325")); - PLAYERS.add(PlayerDetails.create("lisa@google.com", "024-653", "+980742154")); - PLAYERS.add(PlayerDetails.create("anton@google.com", "834-935", "+876423145")); - PLAYERS.add(PlayerDetails.create("bruce@google.com", "284-936", "+09843212345")); - PLAYERS.add(PlayerDetails.create("ray@google.com", "843-073", "+678324123")); - PLAYERS.add(PlayerDetails.create("ron@google.com", "637-738", "+09842354")); - PLAYERS.add(PlayerDetails.create("xavier@google.com", "143-947", "+375245")); - PLAYERS.add(PlayerDetails.create("harriet@google.com", "842-404", "+131243252")); - InMemoryBank wireTransfers = new InMemoryBank(); - Random random = new Random(); - for (int i = 0; i < PLAYERS.size(); i++) { - wireTransfers.setFunds(PLAYERS.get(i).getBankAccount(), - random.nextInt(LotteryConstants.PLAYER_MAX_SALDO)); - } - } - + /** * Program entry point */ public static void main(String[] args) { - Injector injector = Guice.createInjector(new LotteryModule()); + Injector injector = Guice.createInjector(new LotteryTestingModule()); // start new lottery round LotteryAdministration administartion = injector.getInstance(LotteryAdministration.class); @@ -133,22 +75,9 @@ public class App { // submit some lottery tickets LotteryService service = injector.getInstance(LotteryService.class); - submitTickets(service, 20); + SampleData.submitTickets(service, 20); // perform lottery administartion.performLottery(); } - - private static void submitTickets(LotteryService lotteryService, int numTickets) { - for (int i = 0; i < numTickets; i++) { - LotteryTicket ticket = LotteryTicket.create(getRandomPlayerDetails(), LotteryNumbers.createRandom()); - lotteryService.submitTicket(ticket); - } - } - - private static PlayerDetails getRandomPlayerDetails() { - Random random = new Random(); - int idx = random.nextInt(PLAYERS.size()); - return PLAYERS.get(idx); - } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java index 5238edd24..4301c07e3 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java @@ -1,7 +1,84 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.administration; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.iluwatar.hexagonal.domain.LotteryAdministration; +import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotteryService; +import com.iluwatar.hexagonal.module.LotteryModule; +import com.iluwatar.hexagonal.sampledata.SampleData; + +import java.util.Scanner; + /** * Console interface for lottery administration */ public class ConsoleAdministration { + + /** + * Program entry point + */ + public static void main(String[] args) { + Injector injector = Guice.createInjector(new LotteryModule()); + LotteryAdministration administartion = injector.getInstance(LotteryAdministration.class); + LotteryService service = injector.getInstance(LotteryService.class); + SampleData.submitTickets(service, 20); + Scanner scanner = new Scanner(System.in); + boolean exit = false; + while (!exit) { + printMainMenu(); + String cmd = readString(scanner); + if (cmd.equals("1")) { + administartion.getAllSubmittedTickets().forEach((k,v)->System.out.println("Key: " + k + " Value: " + v)); + } else if (cmd.equals("2")) { + LotteryNumbers numbers = administartion.performLottery(); + System.out.println("The winning numbers: " + numbers); + System.out.println("Time to reset the database for next round, eh?"); + } else if (cmd.equals("3")) { + administartion.resetLottery(); + System.out.println("The lottery ticket database was cleared."); + } else if (cmd.equals("4")) { + exit = true; + } else { + System.out.println("Unknown command: " + cmd); + } + } + } + + private static void printMainMenu() { + System.out.println(""); + System.out.println("### Lottery Administration Console ###"); + System.out.println("(1) Show all submitted tickets"); + System.out.println("(2) Perform lottery draw"); + System.out.println("(3) Reset lottery ticket database"); + System.out.println("(4) Exit"); + } + + private static String readString(Scanner scanner) { + System.out.print("> "); + String cmd = scanner.next(); + return cmd; + } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java index 7117397d3..f73390863 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java @@ -41,6 +41,9 @@ public class LotteryAdministration { private final WireTransfers wireTransfers; private final LotteryTicketChecker checker; + /** + * Constructor + */ @Inject public LotteryAdministration(LotteryTicketRepository repository, LotteryNotifications notifications, WireTransfers wireTransfers) { diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java index 69d654657..9ce8d61bd 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java @@ -92,7 +92,12 @@ public class LotteryNumbers { } } } - + + @Override + public String toString() { + return "LotteryNumbers{" + "numbers=" + numbers + '}'; + } + /** * * Helper class for generating random numbers. diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java index e5828cfbf..08064f46c 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java @@ -61,6 +61,11 @@ public class LotteryTicket { return lotteryNumbers; } + @Override + public String toString() { + return playerDetails.toString() + " " + lotteryNumbers.toString(); + } + @Override public int hashCode() { final int prime = 31; diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java index 10042528b..ce193386b 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.domain; import com.iluwatar.hexagonal.database.LotteryTicketRepository; diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java index 710091222..e2aa51792 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java @@ -34,8 +34,17 @@ public class LotteryTicketId { public LotteryTicketId() { id = UUID.randomUUID(); } + + public LotteryTicketId(String str) { + id = UUID.fromString(str); + } public UUID getId() { return id; } + + @Override + public String toString() { + return id.toString(); + } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java index 2fcdb6eb3..1061ad553 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java @@ -70,6 +70,13 @@ public class PlayerDetails { return phoneNumber; } + @Override + public String toString() { + return "PlayerDetails{" + "emailAddress='" + emailAddress + '\'' + + ", bankAccountNumber='" + bankAccountNumber + '\'' + + ", phoneNumber='" + phoneNumber + '\'' + '}'; + } + @Override public int hashCode() { final int prime = 31; diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java similarity index 97% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java index dbaf494c2..c62dbfa54 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/LotteryModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.hexagonal; +package com.iluwatar.hexagonal.module; import com.google.inject.AbstractModule; import com.iluwatar.hexagonal.banking.InMemoryBank; diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryTestingModule.java similarity index 97% rename from hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryTestingModule.java index 22bfa8f01..c934ed43c 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/LotteryTestingModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryTestingModule.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.hexagonal; +package com.iluwatar.hexagonal.module; import com.google.inject.AbstractModule; import com.iluwatar.hexagonal.banking.InMemoryBank; diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java new file mode 100644 index 000000000..1af18118d --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java @@ -0,0 +1,107 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.sampledata; + +import com.iluwatar.hexagonal.banking.InMemoryBank; +import com.iluwatar.hexagonal.domain.LotteryConstants; +import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotteryService; +import com.iluwatar.hexagonal.domain.LotteryTicket; +import com.iluwatar.hexagonal.domain.PlayerDetails; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Utilities for creating sample lottery tickets + */ +public class SampleData { + + private static final List PLAYERS; + + static { + PLAYERS = new ArrayList<>(); + PLAYERS.add(PlayerDetails.create("john@google.com", "312-342", "+3242434242")); + PLAYERS.add(PlayerDetails.create("mary@google.com", "234-987", "+23452346")); + PLAYERS.add(PlayerDetails.create("steve@google.com", "833-836", "+63457543")); + PLAYERS.add(PlayerDetails.create("wayne@google.com", "319-826", "+24626")); + PLAYERS.add(PlayerDetails.create("johnie@google.com", "983-322", "+3635635")); + PLAYERS.add(PlayerDetails.create("andy@google.com", "934-734", "+0898245")); + PLAYERS.add(PlayerDetails.create("richard@google.com", "536-738", "+09845325")); + PLAYERS.add(PlayerDetails.create("kevin@google.com", "453-936", "+2423532")); + PLAYERS.add(PlayerDetails.create("arnold@google.com", "114-988", "+5646346524")); + PLAYERS.add(PlayerDetails.create("ian@google.com", "663-765", "+928394235")); + PLAYERS.add(PlayerDetails.create("robin@google.com", "334-763", "+35448")); + PLAYERS.add(PlayerDetails.create("ted@google.com", "735-964", "+98752345")); + PLAYERS.add(PlayerDetails.create("larry@google.com", "734-853", "+043842423")); + PLAYERS.add(PlayerDetails.create("calvin@google.com", "334-746", "+73294135")); + PLAYERS.add(PlayerDetails.create("jacob@google.com", "444-766", "+358042354")); + PLAYERS.add(PlayerDetails.create("edwin@google.com", "895-345", "+9752435")); + PLAYERS.add(PlayerDetails.create("mary@google.com", "760-009", "+34203542")); + PLAYERS.add(PlayerDetails.create("lolita@google.com", "425-907", "+9872342")); + PLAYERS.add(PlayerDetails.create("bruno@google.com", "023-638", "+673824122")); + PLAYERS.add(PlayerDetails.create("peter@google.com", "335-886", "+5432503945")); + PLAYERS.add(PlayerDetails.create("warren@google.com", "225-946", "+9872341324")); + PLAYERS.add(PlayerDetails.create("monica@google.com", "265-748", "+134124")); + PLAYERS.add(PlayerDetails.create("ollie@google.com", "190-045", "+34453452")); + PLAYERS.add(PlayerDetails.create("yngwie@google.com", "241-465", "+9897641231")); + PLAYERS.add(PlayerDetails.create("lars@google.com", "746-936", "+42345298345")); + PLAYERS.add(PlayerDetails.create("bobbie@google.com", "946-384", "+79831742")); + PLAYERS.add(PlayerDetails.create("tyron@google.com", "310-992", "+0498837412")); + PLAYERS.add(PlayerDetails.create("tyrell@google.com", "032-045", "+67834134")); + PLAYERS.add(PlayerDetails.create("nadja@google.com", "000-346", "+498723")); + PLAYERS.add(PlayerDetails.create("wendy@google.com", "994-989", "+987324454")); + PLAYERS.add(PlayerDetails.create("luke@google.com", "546-634", "+987642435")); + PLAYERS.add(PlayerDetails.create("bjorn@google.com", "342-874", "+7834325")); + PLAYERS.add(PlayerDetails.create("lisa@google.com", "024-653", "+980742154")); + PLAYERS.add(PlayerDetails.create("anton@google.com", "834-935", "+876423145")); + PLAYERS.add(PlayerDetails.create("bruce@google.com", "284-936", "+09843212345")); + PLAYERS.add(PlayerDetails.create("ray@google.com", "843-073", "+678324123")); + PLAYERS.add(PlayerDetails.create("ron@google.com", "637-738", "+09842354")); + PLAYERS.add(PlayerDetails.create("xavier@google.com", "143-947", "+375245")); + PLAYERS.add(PlayerDetails.create("harriet@google.com", "842-404", "+131243252")); + InMemoryBank wireTransfers = new InMemoryBank(); + Random random = new Random(); + for (int i = 0; i < PLAYERS.size(); i++) { + wireTransfers.setFunds(PLAYERS.get(i).getBankAccount(), + random.nextInt(LotteryConstants.PLAYER_MAX_SALDO)); + } + } + + /** + * Inserts lottery tickets into the database based on the sample data + */ + public static void submitTickets(LotteryService lotteryService, int numTickets) { + for (int i = 0; i < numTickets; i++) { + LotteryTicket ticket = LotteryTicket.create(getRandomPlayerDetails(), LotteryNumbers.createRandom()); + lotteryService.submitTicket(ticket); + } + } + + private static PlayerDetails getRandomPlayerDetails() { + Random random = new Random(); + int idx = random.nextInt(PLAYERS.size()); + return PLAYERS.get(idx); + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index e48410982..aade24a91 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -1,7 +1,137 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.service; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.iluwatar.hexagonal.banking.WireTransfers; +import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotteryService; +import com.iluwatar.hexagonal.domain.LotteryTicket; +import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; +import com.iluwatar.hexagonal.domain.LotteryTicketId; +import com.iluwatar.hexagonal.domain.PlayerDetails; +import com.iluwatar.hexagonal.module.LotteryModule; +import com.iluwatar.hexagonal.sampledata.SampleData; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Scanner; +import java.util.Set; + /** * Console interface for lottery players */ public class ConsoleLottery { + + + /** + * Program entry point + */ + public static void main(String[] args) { + Injector injector = Guice.createInjector(new LotteryModule()); + LotteryService service = injector.getInstance(LotteryService.class); + WireTransfers bank = injector.getInstance(WireTransfers.class); + SampleData.submitTickets(service, 20); + Scanner scanner = new Scanner(System.in); + boolean exit = false; + while (!exit) { + printMainMenu(); + String cmd = readString(scanner); + if (cmd.equals("1")) { + System.out.println("What is the account number?"); + String account = readString(scanner); + System.out.println(String.format("The account %s has %d credits.", account, bank.getFunds(account))); + } else if (cmd.equals("2")) { + System.out.println("What is the account number?"); + String account = readString(scanner); + System.out.println("How many credits do you want to deposit?"); + String amount = readString(scanner); + bank.setFunds(account, Integer.parseInt(amount)); + System.out.println(String.format("The account %s now has %d credits.", account, bank.getFunds(account))); + } else if (cmd.equals("3")) { + System.out.println("What is your email address?"); + String email = readString(scanner); + System.out.println("What is your bank account number?"); + String account = readString(scanner); + System.out.println("What is your phone number?"); + String phone = readString(scanner); + PlayerDetails details = PlayerDetails.create(email, account, phone); + System.out.println("Give 4 comma separated lottery numbers?"); + String numbers = readString(scanner); + String[] parts = numbers.split(","); + Set chosen = new HashSet<>(); + for (int i = 0; i < 4; i++) { + chosen.add(Integer.parseInt(parts[i])); + } + LotteryNumbers lotteryNumbers = LotteryNumbers.create(chosen); + LotteryTicket lotteryTicket = LotteryTicket.create(details, lotteryNumbers); + Optional id = service.submitTicket(lotteryTicket); + if (id.isPresent()) { + System.out.println("Submitted lottery ticket with id: " + id.get()); + } else { + System.out.println("Failed submitting lottery ticket - please try again."); + } + } else if (cmd.equals("4")) { + System.out.println("What is the ID of the lottery ticket?"); + String id = readString(scanner); + System.out.println("Give the 4 comma separated winning numbers?"); + String numbers = readString(scanner); + String[] parts = numbers.split(","); + Set winningNumbers = new HashSet<>(); + for (int i = 0; i < 4; i++) { + winningNumbers.add(Integer.parseInt(parts[i])); + } + LotteryTicketCheckResult result = service.checkTicketForPrize( + new LotteryTicketId(id), LotteryNumbers.create(winningNumbers)); + if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { + System.out.println("Congratulations! The lottery ticket has won!"); + } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { + System.out.println("Unfortunately the lottery ticket did not win."); + } else { + System.out.println("Such lottery ticket has not been submitted."); + } + } else if (cmd.equals("5")) { + exit = true; + } else { + System.out.println("Unknown command"); + } + } + } + + private static void printMainMenu() { + System.out.println(""); + System.out.println("### Lottery Service Console ###"); + System.out.println("(1) Query lottery account funds"); + System.out.println("(2) Add funds to lottery account"); + System.out.println("(3) Submit ticket"); + System.out.println("(4) Check ticket"); + System.out.println("(5) Exit"); + } + + private static String readString(Scanner scanner) { + System.out.print("> "); + String cmd = scanner.next(); + return cmd; + } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java index ed6f8d180..943440f07 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java @@ -33,7 +33,7 @@ import java.util.Optional; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; -import com.iluwatar.hexagonal.LotteryTestingModule; +import com.iluwatar.hexagonal.module.LotteryTestingModule; import org.junit.Before; import org.junit.Test; From 4410419914ee89c7eea2382ae49b056451b420cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 11 Sep 2016 10:34:12 +0300 Subject: [PATCH 053/492] Hexagonal pattern: Simplified lottery ticket ids --- .../hexagonal/domain/LotteryTicketId.java | 38 ++++++++++++---- .../hexagonal/service/ConsoleLottery.java | 4 +- .../hexagonal/domain/LotteryTicketIdTest.java | 45 +++++++++++++++++++ 3 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketIdTest.java diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java index e2aa51792..2f8a59bba 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java @@ -22,29 +22,49 @@ */ package com.iluwatar.hexagonal.domain; -import java.util.UUID; - /** * Lottery ticked id */ public class LotteryTicketId { - - private final UUID id; + + private static volatile int numAllocated; + private final int id; public LotteryTicketId() { - id = UUID.randomUUID(); + this.id = numAllocated + 1; + numAllocated++; } - public LotteryTicketId(String str) { - id = UUID.fromString(str); + public LotteryTicketId(int id) { + this.id = id; } - public UUID getId() { + public int getId() { return id; } @Override public String toString() { - return id.toString(); + return String.format("%d", id); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + LotteryTicketId that = (LotteryTicketId) o; + + return id == that.id; + + } + + @Override + public int hashCode() { + return id; } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index aade24a91..5463eca7c 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -32,7 +32,6 @@ import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; import com.iluwatar.hexagonal.module.LotteryModule; -import com.iluwatar.hexagonal.sampledata.SampleData; import java.util.HashSet; import java.util.Optional; @@ -52,7 +51,6 @@ public class ConsoleLottery { Injector injector = Guice.createInjector(new LotteryModule()); LotteryService service = injector.getInstance(LotteryService.class); WireTransfers bank = injector.getInstance(WireTransfers.class); - SampleData.submitTickets(service, 20); Scanner scanner = new Scanner(System.in); boolean exit = false; while (!exit) { @@ -103,7 +101,7 @@ public class ConsoleLottery { winningNumbers.add(Integer.parseInt(parts[i])); } LotteryTicketCheckResult result = service.checkTicketForPrize( - new LotteryTicketId(id), LotteryNumbers.create(winningNumbers)); + new LotteryTicketId(Integer.parseInt(id)), LotteryNumbers.create(winningNumbers)); if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { System.out.println("Congratulations! The lottery ticket has won!"); } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketIdTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketIdTest.java new file mode 100644 index 000000000..c5e4c1541 --- /dev/null +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketIdTest.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.domain; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Tests for lottery ticket id + */ +public class LotteryTicketIdTest { + + @Test + public void testEquals() { + LotteryTicketId ticketId1 = new LotteryTicketId(); + LotteryTicketId ticketId2 = new LotteryTicketId(); + LotteryTicketId ticketId3 = new LotteryTicketId(); + assertFalse(ticketId1.equals(ticketId2)); + assertFalse(ticketId2.equals(ticketId3)); + LotteryTicketId ticketId4 = new LotteryTicketId(ticketId1.getId()); + assertTrue(ticketId1.equals(ticketId4)); + } +} From a85463470ea3a679ac69e6e1c43c2cb7ae512139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 11 Sep 2016 13:53:00 +0300 Subject: [PATCH 054/492] Hexagonal pattern: Add mongo driver dependency --- hexagonal/pom.xml | 4 ++++ pom.xml | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index a73fea48d..ce1a7049a 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -43,5 +43,9 @@ com.google.inject guice + + org.mongodb + mongo-java-driver + diff --git a/pom.xml b/pom.xml index 023579e97..b1ae7d811 100644 --- a/pom.xml +++ b/pom.xml @@ -48,6 +48,7 @@ 2.22 1.4.1 4.0 + 3.3.0 abstract-factory @@ -242,6 +243,11 @@ guice ${guice.version} + + org.mongodb + mongo-java-driver + ${mongo-java-driver.version} + From 626c56730c7dac32eb33bd414ad4a9436736a097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 11 Sep 2016 20:02:34 +0300 Subject: [PATCH 055/492] Hexagonal pattern: Added Mongo based ticket repository and set production configuration to use that --- .../administration/ConsoleAdministration.java | 2 +- .../database/MongoTicketRepository.java | 194 ++++++++++++++++++ .../hexagonal/domain/LotteryNumbers.java | 18 ++ .../hexagonal/domain/LotteryTicket.java | 24 ++- .../hexagonal/module/LotteryModule.java | 4 +- .../hexagonal/sampledata/SampleData.java | 4 +- .../hexagonal/service/ConsoleLottery.java | 2 +- ...java => InMemoryTicketRepositoryTest.java} | 2 +- .../database/MongoTicketRepositoryTest.java | 94 +++++++++ .../hexagonal/domain/LotteryTicketTest.java | 6 +- .../hexagonal/test/LotteryTestUtils.java | 3 +- 11 files changed, 339 insertions(+), 14 deletions(-) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java rename hexagonal/src/test/java/com/iluwatar/hexagonal/database/{LotteryTicketRepositoryTest.java => InMemoryTicketRepositoryTest.java} (98%) create mode 100644 hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java index 4301c07e3..6a846280c 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java @@ -54,7 +54,7 @@ public class ConsoleAdministration { administartion.getAllSubmittedTickets().forEach((k,v)->System.out.println("Key: " + k + " Value: " + v)); } else if (cmd.equals("2")) { LotteryNumbers numbers = administartion.performLottery(); - System.out.println("The winning numbers: " + numbers); + System.out.println("The winning numbers: " + numbers.getNumbersAsString()); System.out.println("Time to reset the database for next round, eh?"); } else if (cmd.equals("3")) { administartion.resetLottery(); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java new file mode 100644 index 000000000..ff0439af8 --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java @@ -0,0 +1,194 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.database; + +import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotteryTicket; +import com.iluwatar.hexagonal.domain.LotteryTicketId; +import com.iluwatar.hexagonal.domain.PlayerDetails; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; + +/** + * Mongo lottery ticket database + */ +public class MongoTicketRepository implements LotteryTicketRepository { + + private static final String DEFAULT_HOST = "localhost"; + private static final int DEFAULT_PORT = 27017; + private static final String DEFAULT_DB = "lotteryDB"; + private static final String DEFAULT_TICKETS_COLLECTION = "lotteryTickets"; + private static final String DEFAULT_COUNTERS_COLLECTION = "counters"; + + private MongoClient mongoClient; + private MongoDatabase database; + private MongoCollection ticketsCollection; + private MongoCollection countersCollection; + + /** + * Constructor + */ + public MongoTicketRepository() { + connect(); + } + + /** + * Constructor accepting parameters + */ + public MongoTicketRepository(String host, int port, String dbName, String ticketsCollectionName, + String countersCollectionName) { + connect(host, port, dbName, ticketsCollectionName, countersCollectionName); + } + + /** + * Connect to database with default parameters + */ + public void connect() { + connect(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_DB, DEFAULT_TICKETS_COLLECTION, DEFAULT_COUNTERS_COLLECTION); + } + + /** + * Connect to database with given parameters + */ + public void connect(String host, int port, String dbName, String ticketsCollectionName, + String countersCollectionName) { + if (mongoClient != null) { + mongoClient.close(); + } + mongoClient = new MongoClient(host , port); + database = mongoClient.getDatabase(dbName); + ticketsCollection = database.getCollection(ticketsCollectionName); + countersCollection = database.getCollection(countersCollectionName); + if (countersCollection.count() <= 0) { + initCounters(); + } + } + + private void initCounters() { + Document doc = new Document("_id", "ticketId").append("seq", 1); + countersCollection.insertOne(doc); + } + + /** + * @return next ticket id + */ + public int getNextId() { + Document find = new Document("_id", "ticketId"); + Document increase = new Document("seq", 1); + Document update = new Document("$inc", increase); + Document result = countersCollection.findOneAndUpdate(find, update); + return result.getInteger("seq"); + } + + /** + * @return mongo client + */ + public MongoClient getMongoClient() { + return mongoClient; + } + + /** + * + * @return mongo database + */ + public MongoDatabase getMongoDatabase() { + return database; + } + + /** + * + * @return tickets collection + */ + public MongoCollection getTicketsCollection() { + return ticketsCollection; + } + + /** + * + * @return counters collection + */ + public MongoCollection getCountersCollection() { + return countersCollection; + } + + @Override + public Optional findById(LotteryTicketId id) { + Document find = new Document("ticketId", id.getId()); + ArrayList results = ticketsCollection.find(find).limit(1).into(new ArrayList()); + if (results.size() > 0) { + LotteryTicket lotteryTicket = docToTicket(results.get(0)); + return Optional.of(lotteryTicket); + } else { + return Optional.empty(); + } + } + + @Override + public Optional save(LotteryTicket ticket) { + int ticketId = getNextId(); + Document doc = new Document("ticketId", ticketId); + doc.put("email", ticket.getPlayerDetails().getEmail()); + doc.put("bank", ticket.getPlayerDetails().getBankAccount()); + doc.put("phone", ticket.getPlayerDetails().getPhoneNumber()); + doc.put("numbers", ticket.getNumbers().getNumbersAsString()); + ticketsCollection.insertOne(doc); + return Optional.of(new LotteryTicketId(ticketId)); + } + + @Override + public Map findAll() { + Map map = new HashMap<>(); + ArrayList docs = ticketsCollection.find(new Document()).into(new ArrayList()); + for (Document doc: docs) { + LotteryTicket lotteryTicket = docToTicket(doc); + map.put(lotteryTicket.getId(), lotteryTicket); + } + return map; + } + + @Override + public void deleteAll() { + ticketsCollection.deleteMany(new Document()); + } + + private LotteryTicket docToTicket(Document doc) { + PlayerDetails playerDetails = PlayerDetails.create(doc.getString("email"), doc.getString("bank"), + doc.getString("phone")); + int[] numArray = Arrays.asList(doc.getString("numbers").split(",")).stream().mapToInt(Integer::parseInt).toArray(); + HashSet numbers = new HashSet<>(); + for (int num: numArray) { + numbers.add(num); + } + LotteryNumbers lotteryNumbers = LotteryNumbers.create(numbers); + return LotteryTicket.create(new LotteryTicketId(doc.getInteger("ticketId")), playerDetails, lotteryNumbers); + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java index 9ce8d61bd..930c919da 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java @@ -22,8 +22,10 @@ */ package com.iluwatar.hexagonal.domain; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.PrimitiveIterator; import java.util.Random; import java.util.Set; @@ -78,6 +80,22 @@ public class LotteryNumbers { public Set getNumbers() { return Collections.unmodifiableSet(numbers); } + + /** + * @return numbers as comma separated string + */ + public String getNumbersAsString() { + List list = new ArrayList<>(); + list.addAll(numbers); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < NUM_NUMBERS; i++) { + builder.append(list.get(i)); + if (i < NUM_NUMBERS - 1) { + builder.append(","); + } + } + return builder.toString(); + } /** * Generates 4 unique random numbers between 1-20 into numbers set. diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java index 08064f46c..3e9ebdae4 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java @@ -29,13 +29,15 @@ package com.iluwatar.hexagonal.domain; */ public class LotteryTicket { + private LotteryTicketId id; private final PlayerDetails playerDetails; private final LotteryNumbers lotteryNumbers; - + /** * Constructor. */ - private LotteryTicket(PlayerDetails details, LotteryNumbers numbers) { + private LotteryTicket(LotteryTicketId id, PlayerDetails details, LotteryNumbers numbers) { + this.id = id; playerDetails = details; lotteryNumbers = numbers; } @@ -43,8 +45,8 @@ public class LotteryTicket { /** * Factory for creating lottery tickets; */ - public static LotteryTicket create(PlayerDetails details, LotteryNumbers numbers) { - return new LotteryTicket(details, numbers); + public static LotteryTicket create(LotteryTicketId id, PlayerDetails details, LotteryNumbers numbers) { + return new LotteryTicket(id, details, numbers); } /** @@ -61,6 +63,20 @@ public class LotteryTicket { return lotteryNumbers; } + /** + * @return id + */ + public LotteryTicketId getId() { + return id; + } + + /** + * set id + */ + public void setId(LotteryTicketId id) { + this.id = id; + } + @Override public String toString() { return playerDetails.toString() + " " + lotteryNumbers.toString(); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java index c62dbfa54..0a0177f25 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java @@ -25,8 +25,8 @@ package com.iluwatar.hexagonal.module; import com.google.inject.AbstractModule; import com.iluwatar.hexagonal.banking.InMemoryBank; import com.iluwatar.hexagonal.banking.WireTransfers; -import com.iluwatar.hexagonal.database.InMemoryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; +import com.iluwatar.hexagonal.database.MongoTicketRepository; import com.iluwatar.hexagonal.notifications.LotteryNotifications; import com.iluwatar.hexagonal.notifications.StdOutNotifications; @@ -36,7 +36,7 @@ import com.iluwatar.hexagonal.notifications.StdOutNotifications; public class LotteryModule extends AbstractModule { @Override protected void configure() { - bind(LotteryTicketRepository.class).to(InMemoryTicketRepository.class); + bind(LotteryTicketRepository.class).to(MongoTicketRepository.class); bind(LotteryNotifications.class).to(StdOutNotifications.class); bind(WireTransfers.class).to(InMemoryBank.class); } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java index 1af18118d..b9c779c34 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java @@ -27,6 +27,7 @@ import com.iluwatar.hexagonal.domain.LotteryConstants; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryService; import com.iluwatar.hexagonal.domain.LotteryTicket; +import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; import java.util.ArrayList; @@ -94,7 +95,8 @@ public class SampleData { */ public static void submitTickets(LotteryService lotteryService, int numTickets) { for (int i = 0; i < numTickets; i++) { - LotteryTicket ticket = LotteryTicket.create(getRandomPlayerDetails(), LotteryNumbers.createRandom()); + LotteryTicket ticket = LotteryTicket.create(new LotteryTicketId(), + getRandomPlayerDetails(), LotteryNumbers.createRandom()); lotteryService.submitTicket(ticket); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index 5463eca7c..afacc35cc 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -83,7 +83,7 @@ public class ConsoleLottery { chosen.add(Integer.parseInt(parts[i])); } LotteryNumbers lotteryNumbers = LotteryNumbers.create(chosen); - LotteryTicket lotteryTicket = LotteryTicket.create(details, lotteryNumbers); + LotteryTicket lotteryTicket = LotteryTicket.create(new LotteryTicketId(), details, lotteryNumbers); Optional id = service.submitTicket(lotteryTicket); if (id.isPresent()) { System.out.println("Submitted lottery ticket with id: " + id.get()); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/LotteryTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/InMemoryTicketRepositoryTest.java similarity index 98% rename from hexagonal/src/test/java/com/iluwatar/hexagonal/database/LotteryTicketRepositoryTest.java rename to hexagonal/src/test/java/com/iluwatar/hexagonal/database/InMemoryTicketRepositoryTest.java index 31cb8f5f0..d32e594a8 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/LotteryTicketRepositoryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/InMemoryTicketRepositoryTest.java @@ -39,7 +39,7 @@ import com.iluwatar.hexagonal.test.LotteryTestUtils; * Tests for {@link LotteryTicketRepository} * */ -public class LotteryTicketRepositoryTest { +public class InMemoryTicketRepositoryTest { private final LotteryTicketRepository repository = new InMemoryTicketRepository(); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java new file mode 100644 index 000000000..dc0d5c7fd --- /dev/null +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java @@ -0,0 +1,94 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.database; + +import com.iluwatar.hexagonal.domain.LotteryNumbers; +import com.iluwatar.hexagonal.domain.LotteryTicket; +import com.iluwatar.hexagonal.domain.LotteryTicketId; +import com.iluwatar.hexagonal.domain.PlayerDetails; +import com.mongodb.MongoClient; +import org.junit.Before; +import org.junit.Test; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Tests for Mongo based ticket repository + */ +public class MongoTicketRepositoryTest { + + private static final String TEST_HOST = "localhost"; + private static final int TEST_PORT = 27017; + private static final String TEST_DB = "lotteryDB"; + private static final String TEST_TICKETS_COLLECTION = "lotteryTickets"; + private static final String TEST_COUNTERS_COLLECTION = "counters"; + + private MongoTicketRepository repository; + + @Before + public void init() { + MongoClient mongoClient = new MongoClient(TEST_HOST, TEST_PORT); + mongoClient.dropDatabase(TEST_DB); + mongoClient.close(); + repository = new MongoTicketRepository(TEST_HOST, TEST_PORT, TEST_DB, TEST_TICKETS_COLLECTION, + TEST_COUNTERS_COLLECTION); + } + + @Test + public void testSetup() { + assertTrue(repository.getCountersCollection().count() == 1); + assertTrue(repository.getTicketsCollection().count() == 0); + } + + @Test + public void testNextId() { + assertEquals(1, repository.getNextId()); + assertEquals(2, repository.getNextId()); + assertEquals(3, repository.getNextId()); + } + + @Test + public void testCrudOperations() { + // create new lottery ticket and save it + PlayerDetails details = PlayerDetails.create("foo@bar.com", "123-123", "07001234"); + LotteryNumbers random = LotteryNumbers.createRandom(); + LotteryTicket original = LotteryTicket.create(new LotteryTicketId(), details, random); + Optional saved = repository.save(original); + assertEquals(1, repository.getTicketsCollection().count()); + assertTrue(saved.isPresent()); + // fetch the saved lottery ticket from database and check its contents + Optional found = repository.findById(saved.get()); + assertTrue(found.isPresent()); + LotteryTicket ticket = found.get(); + assertEquals("foo@bar.com", ticket.getPlayerDetails().getEmail()); + assertEquals("123-123", ticket.getPlayerDetails().getBankAccount()); + assertEquals("07001234", ticket.getPlayerDetails().getPhoneNumber()); + assertEquals(original.getNumbers(), ticket.getNumbers()); + // clear the collection + repository.deleteAll(); + assertEquals(0, repository.getTicketsCollection().count()); + } +} diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java index e1918686a..4840dc897 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java @@ -36,14 +36,14 @@ public class LotteryTicketTest { public void testEquals() { PlayerDetails details1 = PlayerDetails.create("bob@foo.bar", "1212-121212", "+34332322"); LotteryNumbers numbers1 = LotteryNumbers.create(new HashSet(Arrays.asList(1, 2, 3, 4))); - LotteryTicket ticket1 = LotteryTicket.create(details1, numbers1); + LotteryTicket ticket1 = LotteryTicket.create(new LotteryTicketId(), details1, numbers1); PlayerDetails details2 = PlayerDetails.create("bob@foo.bar", "1212-121212", "+34332322"); LotteryNumbers numbers2 = LotteryNumbers.create(new HashSet(Arrays.asList(1, 2, 3, 4))); - LotteryTicket ticket2 = LotteryTicket.create(details2, numbers2); + LotteryTicket ticket2 = LotteryTicket.create(new LotteryTicketId(), details2, numbers2); assertEquals(ticket1, ticket2); PlayerDetails details3 = PlayerDetails.create("elsa@foo.bar", "1223-121212", "+49332322"); LotteryNumbers numbers3 = LotteryNumbers.create(new HashSet(Arrays.asList(1, 2, 3, 8))); - LotteryTicket ticket3 = LotteryTicket.create(details3, numbers3); + LotteryTicket ticket3 = LotteryTicket.create(new LotteryTicketId(), details3, numbers3); assertFalse(ticket1.equals(ticket3)); } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java index 883c8127f..02304296f 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java @@ -28,6 +28,7 @@ import java.util.Set; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; +import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; /** @@ -51,6 +52,6 @@ public class LotteryTestUtils { Set givenNumbers) { PlayerDetails details = PlayerDetails.create(email, account, phone); LotteryNumbers numbers = LotteryNumbers.create(givenNumbers); - return LotteryTicket.create(details, numbers); + return LotteryTicket.create(new LotteryTicketId(), details, numbers); } } From 9a90f2de1f50557e584d3a0ced4d134c8c702090 Mon Sep 17 00:00:00 2001 From: WSSIA Date: Sun, 11 Sep 2016 18:45:51 +0100 Subject: [PATCH 056/492] Changes based on code review --- event-asynchronous/README.md | 2 + .../etc/event-asynchronous.ucls | 30 +++++---- .../com/iluwatar/event/asynchronous/App.java | 63 ++++++++++--------- .../iluwatar/event/asynchronous/Event.java | 14 ++--- .../event/asynchronous/EventManager.java | 59 ++++++++++++----- .../asynchronous/ThreadCompleteListener.java | 2 +- .../asynchronous/EventAsynchronousTest.java | 37 ++++++----- 7 files changed, 125 insertions(+), 82 deletions(-) diff --git a/event-asynchronous/README.md b/event-asynchronous/README.md index 59e6e8b33..dde434aba 100644 --- a/event-asynchronous/README.md +++ b/event-asynchronous/README.md @@ -5,6 +5,8 @@ folder: event-asynchronous permalink: /patterns/event-asynchronous/ categories: Other tags: + - difficulty-intermediate + - performance - Java --- diff --git a/event-asynchronous/etc/event-asynchronous.ucls b/event-asynchronous/etc/event-asynchronous.ucls index cc7241044..df09fc28d 100644 --- a/event-asynchronous/etc/event-asynchronous.ucls +++ b/event-asynchronous/etc/event-asynchronous.ucls @@ -65,12 +65,15 @@ - - - - + + + + + + + - + @@ -78,19 +81,24 @@ - + + + - - - - + + + + + + + - + diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java index fa6116b46..f951af07c 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java @@ -48,6 +48,8 @@ import java.util.Scanner; */ public class App { + public static final String PROP_FILE_NAME = "config.properties"; + boolean interactiveMode = false; /** @@ -68,15 +70,14 @@ public class App { */ public void setUp() { Properties prop = new Properties(); - String propFileName = "config.properties"; - InputStream inputStream = App.class.getClassLoader().getResourceAsStream(propFileName); + InputStream inputStream = App.class.getClassLoader().getResourceAsStream(PROP_FILE_NAME); if (inputStream != null) { try { prop.load(inputStream); } catch (IOException e) { - System.out.println(propFileName + " was not found. Defaulting to non-interactive mode."); + System.out.println(PROP_FILE_NAME + " was not found. Defaulting to non-interactive mode."); } String property = prop.getProperty("INTERACTIVE_MODE"); if (property.equalsIgnoreCase("YES")) { @@ -104,23 +105,23 @@ public class App { try { // Create an Asynchronous event. - int aEventId = eventManager.createAsyncEvent(60); + int aEventId = eventManager.createAsync(60); System.out.println("Event [" + aEventId + "] has been created."); - eventManager.startEvent(aEventId); + eventManager.start(aEventId); System.out.println("Event [" + aEventId + "] has been started."); // Create a Synchronous event. - int sEventId = eventManager.createSyncEvent(60); + int sEventId = eventManager.create(60); System.out.println("Event [" + sEventId + "] has been created."); - eventManager.startEvent(sEventId); + eventManager.start(sEventId); System.out.println("Event [" + sEventId + "] has been started."); - eventManager.getStatus(aEventId); - eventManager.getStatus(sEventId); + eventManager.status(aEventId); + eventManager.status(sEventId); - eventManager.stopEvent(aEventId); + eventManager.cancel(aEventId); System.out.println("Event [" + aEventId + "] has been stopped."); - eventManager.stopEvent(sEventId); + eventManager.cancel(sEventId); System.out.println("Event [" + sEventId + "] has been stopped."); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException @@ -136,35 +137,33 @@ public class App { EventManager eventManager = new EventManager(); Scanner s = new Scanner(System.in); - int option = 0; - option = -1; + int option = -1; while (option != 5) { - System.out - .println("(1) START_EVENT \n(2) STOP_EVENT \n(3) STATUS_OF_EVENT \n(4) STATUS_OF_ALL_EVENTS \n(5) EXIT"); + System.out.println("Hello. Would you like to boil some eggs?"); + System.out.println( + "(1) BOIL AN EGG \n(2) STOP BOILING THIS EGG \n(3) HOW IS MY EGG? \n(4) HOW ARE MY EGGS? \n(5) EXIT"); System.out.print("Choose [1,2,3,4,5]: "); option = s.nextInt(); if (option == 1) { s.nextLine(); - System.out.print("(A)sync or (S)ync event?: "); + System.out.print("Boil multiple eggs at once (A) or boil them one-by-one (S)?: "); String eventType = s.nextLine(); - System.out.print("How long should this event run for (in seconds)?: "); + System.out.print("How long should this egg be boiled for (in seconds)?: "); int eventTime = s.nextInt(); if (eventType.equalsIgnoreCase("A")) { try { - int eventId = eventManager.createAsyncEvent(eventTime); - System.out.println("Event [" + eventId + "] has been created."); - eventManager.startEvent(eventId); - System.out.println("Event [" + eventId + "] has been started."); + int eventId = eventManager.createAsync(eventTime); + eventManager.start(eventId); + System.out.println("Egg [" + eventId + "] is being boiled."); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { System.out.println(e.getMessage()); } } else if (eventType.equalsIgnoreCase("S")) { try { - int eventId = eventManager.createSyncEvent(eventTime); - System.out.println("Event [" + eventId + "] has been created."); - eventManager.startEvent(eventId); - System.out.println("Event [" + eventId + "] has been started."); + int eventId = eventManager.create(eventTime); + eventManager.start(eventId); + System.out.println("Egg [" + eventId + "] is being boiled."); } catch (MaxNumOfEventsAllowedException | InvalidOperationException | LongRunningEventException | EventDoesNotExistException e) { System.out.println(e.getMessage()); @@ -173,24 +172,26 @@ public class App { System.out.println("Unknown event type."); } } else if (option == 2) { - System.out.print("Event ID: "); + System.out.print("Which egg?: "); int eventId = s.nextInt(); try { - eventManager.stopEvent(eventId); - System.out.println("Event [" + eventId + "] has been stopped."); + eventManager.cancel(eventId); + System.out.println("Egg [" + eventId + "] is removed from boiler."); } catch (EventDoesNotExistException e) { System.out.println(e.getMessage()); } } else if (option == 3) { - System.out.print("Event ID: "); + System.out.print("Which egg?: "); int eventId = s.nextInt(); try { - eventManager.getStatus(eventId); + eventManager.status(eventId); } catch (EventDoesNotExistException e) { System.out.println(e.getMessage()); } } else if (option == 4) { - eventManager.getStatusOfAllEvents(); + eventManager.statusOfAllEvents(); + } else if (option == 5) { + eventManager.shutdown(); } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java index 4b4fe1d94..1cb04acdc 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java @@ -26,11 +26,10 @@ public class Event implements IEvent, Runnable { private int eventId; private int eventTime; private Thread thread; - private long counter = 0; private boolean isComplete = false; private ThreadCompleteListener eventListener; - public Event(int eventId, int eventTime) { + public Event(final int eventId, final int eventTime) { this.eventId = eventId; this.eventTime = eventTime; } @@ -49,9 +48,9 @@ public class Event implements IEvent, Runnable { @Override public void status() { if (!isComplete) { - System.out.println("[" + eventId + "] I am at not done. [" + counter + "%]"); + System.out.println("[" + eventId + "] is not done."); } else { - System.out.println("[" + eventId + "] I am done."); + System.out.println("[" + eventId + "] is done."); } } @@ -61,14 +60,13 @@ public class Event implements IEvent, Runnable { long endTime = currentTime + (eventTime * 1000); while (System.currentTimeMillis() < endTime) { try { - counter += 1; Thread.sleep(5000); // Sleep for 5 seconds. } catch (InterruptedException e) { return; } } isComplete = true; - notifyListener(); + completed(); } public final void addListener(final ThreadCompleteListener listener) { @@ -79,9 +77,9 @@ public class Event implements IEvent, Runnable { this.eventListener = null; } - private final void notifyListener() { + private final void completed() { if (eventListener != null) { - eventListener.notifyOfThreadComplete(eventId); + eventListener.completedEventHandler(eventId); } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java index d3278594f..e65816cec 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java @@ -32,10 +32,10 @@ import java.util.concurrent.ConcurrentHashMap; */ public class EventManager implements ThreadCompleteListener { - private int minId = 1; - private int maxId = Integer.MAX_VALUE - 1; // Be cautious of overflows. - private int maxRunningEvents = 1000; // no particular reason. Just don't wanna have too many running events. :) - private int maxEventTime = 1800; // in seconds / 30 minutes. + public static final int MAX_RUNNING_EVENTS = 1000; // Just don't wanna have too many running events. :) + public static final int MIN_ID = 1; + public static final int MAX_ID = MAX_RUNNING_EVENTS; + public static final int MAX_EVENT_TIME = 1800; // in seconds / 30 minutes. private int currentlyRunningSyncEvent = -1; private Random rand; private Map eventPool; @@ -46,7 +46,7 @@ public class EventManager implements ThreadCompleteListener { */ public EventManager() { rand = new Random(1); - eventPool = new ConcurrentHashMap(maxRunningEvents); + eventPool = new ConcurrentHashMap(MAX_RUNNING_EVENTS); } @@ -59,7 +59,7 @@ public class EventManager implements ThreadCompleteListener { * @throws InvalidOperationException No new synchronous events can be created when one is already running. * @throws LongRunningEventException Long running events are not allowed in the app. */ - public int createSyncEvent(int eventTime) + public int create(int eventTime) throws MaxNumOfEventsAllowedException, InvalidOperationException, LongRunningEventException { int eventId = createEvent(eventTime); if (currentlyRunningSyncEvent != -1) { @@ -79,18 +79,18 @@ public class EventManager implements ThreadCompleteListener { * @throws MaxNumOfEventsAllowedException When too many events are running at a time. * @throws LongRunningEventException Long running events are not allowed in the app. */ - public int createAsyncEvent(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { + public int createAsync(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { return createEvent(eventTime); } private int createEvent(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { - if (eventPool.size() == maxRunningEvents) { + if (eventPool.size() == MAX_RUNNING_EVENTS) { throw new MaxNumOfEventsAllowedException("Too many events are running at the moment. Please try again later."); } - if (eventTime >= maxEventTime) { + if (eventTime >= MAX_EVENT_TIME) { throw new LongRunningEventException( - "Maximum event time allowed is " + maxEventTime + " seconds. Please try again."); + "Maximum event time allowed is " + MAX_EVENT_TIME + " seconds. Please try again."); } int newEventId = generateId(); @@ -108,7 +108,7 @@ public class EventManager implements ThreadCompleteListener { * @param eventId The event that needs to be started. * @throws EventDoesNotExistException If event does not exist in our eventPool. */ - public void startEvent(int eventId) throws EventDoesNotExistException { + public void start(int eventId) throws EventDoesNotExistException { if (!eventPool.containsKey(eventId)) { throw new EventDoesNotExistException(eventId + " does not exist."); } @@ -122,7 +122,7 @@ public class EventManager implements ThreadCompleteListener { * @param eventId The event that needs to be stopped. * @throws EventDoesNotExistException If event does not exist in our eventPool. */ - public void stopEvent(int eventId) throws EventDoesNotExistException { + public void cancel(int eventId) throws EventDoesNotExistException { if (!eventPool.containsKey(eventId)) { throw new EventDoesNotExistException(eventId + " does not exist."); } @@ -141,7 +141,7 @@ public class EventManager implements ThreadCompleteListener { * @param eventId The event to inquire status of. * @throws EventDoesNotExistException If event does not exist in our eventPool. */ - public void getStatus(int eventId) throws EventDoesNotExistException { + public void status(int eventId) throws EventDoesNotExistException { if (!eventPool.containsKey(eventId)) { throw new EventDoesNotExistException(eventId + " does not exist."); } @@ -153,7 +153,7 @@ public class EventManager implements ThreadCompleteListener { * Gets status of all running events. */ @SuppressWarnings("rawtypes") - public void getStatusOfAllEvents() { + public void statusOfAllEvents() { Iterator it = eventPool.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); @@ -161,6 +161,18 @@ public class EventManager implements ThreadCompleteListener { } } + /** + * Stop all running events. + */ + @SuppressWarnings("rawtypes") + public void shutdown() { + Iterator it = eventPool.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + ((Event) pair.getValue()).stop(); + } + } + /** * Returns a pseudo-random number between min and max, inclusive. The difference between min and max can be at most * Integer.MAX_VALUE - 1. @@ -168,9 +180,9 @@ public class EventManager implements ThreadCompleteListener { private int generateId() { // nextInt is normally exclusive of the top value, // so add 1 to make it inclusive - int randomNum = rand.nextInt((maxId - minId) + 1) + minId; + int randomNum = rand.nextInt((MAX_ID - MIN_ID) + 1) + MIN_ID; while (eventPool.containsKey(randomNum)) { - randomNum = rand.nextInt((maxId - minId) + 1) + minId; + randomNum = rand.nextInt((MAX_ID - MIN_ID) + 1) + MIN_ID; } return randomNum; @@ -180,9 +192,22 @@ public class EventManager implements ThreadCompleteListener { * Callback from an {@link Event} (once it is complete). The Event is then removed from the pool. */ @Override - public void notifyOfThreadComplete(int eventId) { + public void completedEventHandler(int eventId) { eventPool.get(eventId).status(); eventPool.remove(eventId); } + /** + * Getter method for event pool. + */ + public Map getEventPool() { + return eventPool; + } + + /** + * Get number of currently running Synchronous events. + */ + public int numOfCurrentlyRunningSyncEvent() { + return currentlyRunningSyncEvent; + } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java index 88f300634..fd62a3e80 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java @@ -17,5 +17,5 @@ package com.iluwatar.event.asynchronous; public interface ThreadCompleteListener { - void notifyOfThreadComplete(final int eventId); + void completedEventHandler(final int eventId); } diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java index 392c7fba6..6565d5bad 100644 --- a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java @@ -16,6 +16,8 @@ */ package com.iluwatar.event.asynchronous; +import static org.junit.Assert.assertTrue; + import org.junit.Before; import org.junit.Test; @@ -36,9 +38,13 @@ public class EventAsynchronousTest { public void testAsynchronousEvent() { EventManager eventManager = new EventManager(); try { - int aEventId = eventManager.createAsyncEvent(60); - eventManager.startEvent(aEventId); - eventManager.stopEvent(aEventId); + int aEventId = eventManager.createAsync(60); + eventManager.start(aEventId); + assertTrue(eventManager.getEventPool().size() == 1); + assertTrue(eventManager.getEventPool().size() < EventManager.MAX_RUNNING_EVENTS); + assertTrue(eventManager.numOfCurrentlyRunningSyncEvent() == -1); + eventManager.cancel(aEventId); + assertTrue(eventManager.getEventPool().size() == 0); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { System.out.println(e.getMessage()); } @@ -48,25 +54,28 @@ public class EventAsynchronousTest { public void testSynchronousEvent() { EventManager eventManager = new EventManager(); try { - int sEventId = eventManager.createSyncEvent(60); - eventManager.startEvent(sEventId); - eventManager.stopEvent(sEventId); + int sEventId = eventManager.create(60); + eventManager.start(sEventId); + assertTrue(eventManager.getEventPool().size() == 1); + assertTrue(eventManager.getEventPool().size() < EventManager.MAX_RUNNING_EVENTS); + assertTrue(eventManager.numOfCurrentlyRunningSyncEvent() != -1); + eventManager.cancel(sEventId); + assertTrue(eventManager.getEventPool().size() == 0); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { System.out.println(e.getMessage()); } } - @Test - public void testUnsuccessfulSynchronousEvent() { + @Test(expected = InvalidOperationException.class) + public void testUnsuccessfulSynchronousEvent() throws InvalidOperationException { EventManager eventManager = new EventManager(); try { - int sEventId = eventManager.createSyncEvent(60); - eventManager.startEvent(sEventId); - sEventId = eventManager.createSyncEvent(60); - eventManager.startEvent(sEventId); - } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException - | InvalidOperationException e) { + int sEventId = eventManager.create(60); + eventManager.start(sEventId); + sEventId = eventManager.create(60); + eventManager.start(sEventId); + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { System.out.println(e.getMessage()); } } From 59e6a0af853c8064735302bf8eae6847bb54f6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 11 Sep 2016 22:16:50 +0300 Subject: [PATCH 057/492] Hexagonal pattern: Ignore Mongo repository test --- .../iluwatar/hexagonal/database/MongoTicketRepositoryTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java index dc0d5c7fd..09a2772bd 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java @@ -28,6 +28,7 @@ import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; import com.mongodb.MongoClient; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import java.util.Optional; @@ -38,6 +39,7 @@ import static org.junit.Assert.assertTrue; /** * Tests for Mongo based ticket repository */ +@Ignore public class MongoTicketRepositoryTest { private static final String TEST_HOST = "localhost"; From e685512ed59a46f02e3b7670b8ee6731fc3279e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 11 Sep 2016 23:19:02 +0300 Subject: [PATCH 058/492] Hexagonal pattern: Added Mongo based banking adapter and bound it in Guice production module --- .../iluwatar/hexagonal/banking/MongoBank.java | 134 ++++++++++++++++++ .../hexagonal/module/LotteryModule.java | 4 +- ...ansfersTest.java => InMemoryBankTest.java} | 2 +- .../hexagonal/banking/MongoBankTest.java | 68 +++++++++ .../database/MongoTicketRepositoryTest.java | 6 +- 5 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java rename hexagonal/src/test/java/com/iluwatar/hexagonal/banking/{WireTransfersTest.java => InMemoryBankTest.java} (98%) create mode 100644 hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java new file mode 100644 index 000000000..3da65e156 --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java @@ -0,0 +1,134 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.banking; + +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.UpdateOptions; +import org.bson.Document; + +import java.util.ArrayList; + +/** + * Mongo based banking adapter + */ +public class MongoBank implements WireTransfers { + + private static final String DEFAULT_HOST = "localhost"; + private static final int DEFAULT_PORT = 27017; + private static final String DEFAULT_DB = "lotteryDB"; + private static final String DEFAULT_ACCOUNTS_COLLECTION = "accounts"; + + private MongoClient mongoClient; + private MongoDatabase database; + private MongoCollection accountsCollection; + + /** + * Constructor + */ + public MongoBank() { + connect(); + } + + /** + * Constructor accepting parameters + */ + public MongoBank(String host, int port, String dbName, String accountsCollectionName) { + connect(host, port, dbName, accountsCollectionName); + } + + /** + * Connect to database with default parameters + */ + public void connect() { + connect(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_DB, DEFAULT_ACCOUNTS_COLLECTION); + } + + /** + * Connect to database with given parameters + */ + public void connect(String host, int port, String dbName, String accountsCollectionName) { + if (mongoClient != null) { + mongoClient.close(); + } + mongoClient = new MongoClient(host , port); + database = mongoClient.getDatabase(dbName); + accountsCollection = database.getCollection(accountsCollectionName); + } + + /** + * @return mongo client + */ + public MongoClient getMongoClient() { + return mongoClient; + } + + /** + * + * @return mongo database + */ + public MongoDatabase getMongoDatabase() { + return database; + } + + /** + * + * @return accounts collection + */ + public MongoCollection getAccountsCollection() { + return accountsCollection; + } + + + @Override + public void setFunds(String bankAccount, int amount) { + Document search = new Document("_id", bankAccount); + Document update = new Document("_id", bankAccount).append("funds", amount); + accountsCollection.updateOne(search, new Document("$set", update), new UpdateOptions().upsert(true)); + } + + @Override + public int getFunds(String bankAccount) { + Document search = new Document("_id", bankAccount); + ArrayList results = accountsCollection.find(search).limit(1).into(new ArrayList()); + if (results.size() > 0) { + return results.get(0).getInteger("funds"); + } else { + return 0; + } + } + + @Override + public boolean transferFunds(int amount, String sourceBackAccount, String destinationBankAccount) { + int sourceFunds = getFunds(sourceBackAccount); + if (sourceFunds < amount) { + return false; + } else { + int destFunds = getFunds(destinationBankAccount); + setFunds(sourceBackAccount, sourceFunds - amount); + setFunds(destinationBankAccount, destFunds + amount); + return true; + } + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java index 0a0177f25..c9bc301fc 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java @@ -23,7 +23,7 @@ package com.iluwatar.hexagonal.module; import com.google.inject.AbstractModule; -import com.iluwatar.hexagonal.banking.InMemoryBank; +import com.iluwatar.hexagonal.banking.MongoBank; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.database.MongoTicketRepository; @@ -38,6 +38,6 @@ public class LotteryModule extends AbstractModule { protected void configure() { bind(LotteryTicketRepository.class).to(MongoTicketRepository.class); bind(LotteryNotifications.class).to(StdOutNotifications.class); - bind(WireTransfers.class).to(InMemoryBank.class); + bind(WireTransfers.class).to(MongoBank.class); } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/WireTransfersTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/InMemoryBankTest.java similarity index 98% rename from hexagonal/src/test/java/com/iluwatar/hexagonal/banking/WireTransfersTest.java rename to hexagonal/src/test/java/com/iluwatar/hexagonal/banking/InMemoryBankTest.java index 25fbf460c..c5efda240 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/WireTransfersTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/InMemoryBankTest.java @@ -32,7 +32,7 @@ import org.junit.Test; * Tests for banking * */ -public class WireTransfersTest { +public class InMemoryBankTest { private final WireTransfers bank = new InMemoryBank(); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java new file mode 100644 index 000000000..ad142f028 --- /dev/null +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java @@ -0,0 +1,68 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.banking; + +import com.mongodb.MongoClient; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for Mongo banking adapter + */ +@Ignore +public class MongoBankTest { + + private static final String TEST_HOST = "localhost"; + private static final int TEST_PORT = 27017; + private static final String TEST_DB = "lotteryDBTest"; + private static final String TEST_ACCOUNTS_COLLECTION = "testAccounts"; + + private MongoBank mongoBank; + + @Before + public void init() { + MongoClient mongoClient = new MongoClient(TEST_HOST, TEST_PORT); + mongoClient.dropDatabase(TEST_DB); + mongoClient.close(); + mongoBank = new MongoBank(TEST_HOST, TEST_PORT, TEST_DB, TEST_ACCOUNTS_COLLECTION); + } + + @Test + public void testSetup() { + assertEquals(0, mongoBank.getAccountsCollection().count()); + } + + @Test + public void testFundTransfers() { + assertEquals(0, mongoBank.getFunds("000-000")); + mongoBank.setFunds("000-000", 10); + assertEquals(10, mongoBank.getFunds("000-000")); + assertEquals(0, mongoBank.getFunds("111-111")); + mongoBank.transferFunds(9, "000-000", "111-111"); + assertEquals(1, mongoBank.getFunds("000-000")); + assertEquals(9, mongoBank.getFunds("111-111")); + } +} diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java index 09a2772bd..45fa1cc67 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java @@ -44,9 +44,9 @@ public class MongoTicketRepositoryTest { private static final String TEST_HOST = "localhost"; private static final int TEST_PORT = 27017; - private static final String TEST_DB = "lotteryDB"; - private static final String TEST_TICKETS_COLLECTION = "lotteryTickets"; - private static final String TEST_COUNTERS_COLLECTION = "counters"; + private static final String TEST_DB = "lotteryTestDB"; + private static final String TEST_TICKETS_COLLECTION = "lotteryTestTickets"; + private static final String TEST_COUNTERS_COLLECTION = "testCounters"; private MongoTicketRepository repository; From 27e8cb7f2d28bcc09c3cd0babe8ed901e1bd3804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 14 Sep 2016 19:25:26 +0300 Subject: [PATCH 059/492] Hexagonal pattern: Add separate class for Mongo connection properties --- .../iluwatar/hexagonal/banking/MongoBank.java | 14 ++-- .../database/MongoTicketRepository.java | 14 ++-- .../mongo/MongoConnectionProperties.java | 80 +++++++++++++++++++ .../hexagonal/banking/MongoBankTest.java | 8 +- .../database/MongoTicketRepositoryTest.java | 8 +- 5 files changed, 102 insertions(+), 22 deletions(-) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionProperties.java diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java index 3da65e156..2a18d8986 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java @@ -22,6 +22,7 @@ */ package com.iluwatar.hexagonal.banking; +import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -35,8 +36,6 @@ import java.util.ArrayList; */ public class MongoBank implements WireTransfers { - private static final String DEFAULT_HOST = "localhost"; - private static final int DEFAULT_PORT = 27017; private static final String DEFAULT_DB = "lotteryDB"; private static final String DEFAULT_ACCOUNTS_COLLECTION = "accounts"; @@ -54,25 +53,26 @@ public class MongoBank implements WireTransfers { /** * Constructor accepting parameters */ - public MongoBank(String host, int port, String dbName, String accountsCollectionName) { - connect(host, port, dbName, accountsCollectionName); + public MongoBank(String dbName, String accountsCollectionName) { + connect(dbName, accountsCollectionName); } /** * Connect to database with default parameters */ public void connect() { - connect(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_DB, DEFAULT_ACCOUNTS_COLLECTION); + connect(DEFAULT_DB, DEFAULT_ACCOUNTS_COLLECTION); } /** * Connect to database with given parameters */ - public void connect(String host, int port, String dbName, String accountsCollectionName) { + public void connect(String dbName, String accountsCollectionName) { if (mongoClient != null) { mongoClient.close(); } - mongoClient = new MongoClient(host , port); + MongoConnectionProperties properties = new MongoConnectionProperties().load(); + mongoClient = new MongoClient(properties.getHost(), properties.getPort()); database = mongoClient.getDatabase(dbName); accountsCollection = database.getCollection(accountsCollectionName); } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java index ff0439af8..73ff40b78 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java @@ -26,6 +26,7 @@ import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; +import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -43,8 +44,6 @@ import java.util.Optional; */ public class MongoTicketRepository implements LotteryTicketRepository { - private static final String DEFAULT_HOST = "localhost"; - private static final int DEFAULT_PORT = 27017; private static final String DEFAULT_DB = "lotteryDB"; private static final String DEFAULT_TICKETS_COLLECTION = "lotteryTickets"; private static final String DEFAULT_COUNTERS_COLLECTION = "counters"; @@ -64,27 +63,28 @@ public class MongoTicketRepository implements LotteryTicketRepository { /** * Constructor accepting parameters */ - public MongoTicketRepository(String host, int port, String dbName, String ticketsCollectionName, + public MongoTicketRepository(String dbName, String ticketsCollectionName, String countersCollectionName) { - connect(host, port, dbName, ticketsCollectionName, countersCollectionName); + connect(dbName, ticketsCollectionName, countersCollectionName); } /** * Connect to database with default parameters */ public void connect() { - connect(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_DB, DEFAULT_TICKETS_COLLECTION, DEFAULT_COUNTERS_COLLECTION); + connect(DEFAULT_DB, DEFAULT_TICKETS_COLLECTION, DEFAULT_COUNTERS_COLLECTION); } /** * Connect to database with given parameters */ - public void connect(String host, int port, String dbName, String ticketsCollectionName, + public void connect(String dbName, String ticketsCollectionName, String countersCollectionName) { if (mongoClient != null) { mongoClient.close(); } - mongoClient = new MongoClient(host , port); + MongoConnectionProperties properties = new MongoConnectionProperties().load(); + mongoClient = new MongoClient(properties.getHost(), properties.getPort()); database = mongoClient.getDatabase(dbName); ticketsCollection = database.getCollection(ticketsCollectionName); countersCollection = database.getCollection(countersCollectionName); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionProperties.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionProperties.java new file mode 100644 index 000000000..20b1876f6 --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionProperties.java @@ -0,0 +1,80 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.mongo; + +import java.io.FileInputStream; +import java.util.Properties; + +/** + * Mongo connection properties + */ +public class MongoConnectionProperties { + + private static final String DEFAULT_HOST = "localhost"; + private static final int DEFAULT_PORT = 27017; + + private String host; + private int port; + + /** + * Constructor + */ + public MongoConnectionProperties() { + this.host = DEFAULT_HOST; + this.port = DEFAULT_PORT; + } + + /** + * @return host name + */ + public String getHost() { + return host; + } + + /** + * @return port number + */ + public int getPort() { + return port; + } + + /** + * Try to load connection properties from file. + * Fall back to default connection properties. + */ + public MongoConnectionProperties load() { + String path = System.getProperty("hexagonal.properties.path"); + Properties properties = new Properties(); + if (path != null) { + try (FileInputStream fin = new FileInputStream(path)) { + properties.load(fin); + this.host = properties.getProperty("host"); + this.port = Integer.parseInt(properties.getProperty("port")); + } catch (Exception e) { + // error occurred, use default properties + e.printStackTrace(); + } + } + return this; + } +} diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java index ad142f028..26041b174 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java @@ -22,6 +22,7 @@ */ package com.iluwatar.hexagonal.banking; +import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; import com.mongodb.MongoClient; import org.junit.Before; import org.junit.Ignore; @@ -35,8 +36,6 @@ import static org.junit.Assert.assertEquals; @Ignore public class MongoBankTest { - private static final String TEST_HOST = "localhost"; - private static final int TEST_PORT = 27017; private static final String TEST_DB = "lotteryDBTest"; private static final String TEST_ACCOUNTS_COLLECTION = "testAccounts"; @@ -44,10 +43,11 @@ public class MongoBankTest { @Before public void init() { - MongoClient mongoClient = new MongoClient(TEST_HOST, TEST_PORT); + MongoConnectionProperties properties = new MongoConnectionProperties().load(); + MongoClient mongoClient = new MongoClient(properties.getHost(), properties.getPort()); mongoClient.dropDatabase(TEST_DB); mongoClient.close(); - mongoBank = new MongoBank(TEST_HOST, TEST_PORT, TEST_DB, TEST_ACCOUNTS_COLLECTION); + mongoBank = new MongoBank(TEST_DB, TEST_ACCOUNTS_COLLECTION); } @Test diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java index 45fa1cc67..a29b535f6 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java @@ -26,6 +26,7 @@ import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; +import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; import com.mongodb.MongoClient; import org.junit.Before; import org.junit.Ignore; @@ -42,8 +43,6 @@ import static org.junit.Assert.assertTrue; @Ignore public class MongoTicketRepositoryTest { - private static final String TEST_HOST = "localhost"; - private static final int TEST_PORT = 27017; private static final String TEST_DB = "lotteryTestDB"; private static final String TEST_TICKETS_COLLECTION = "lotteryTestTickets"; private static final String TEST_COUNTERS_COLLECTION = "testCounters"; @@ -52,10 +51,11 @@ public class MongoTicketRepositoryTest { @Before public void init() { - MongoClient mongoClient = new MongoClient(TEST_HOST, TEST_PORT); + MongoConnectionProperties properties = new MongoConnectionProperties().load(); + MongoClient mongoClient = new MongoClient(properties.getHost(), properties.getPort()); mongoClient.dropDatabase(TEST_DB); mongoClient.close(); - repository = new MongoTicketRepository(TEST_HOST, TEST_PORT, TEST_DB, TEST_TICKETS_COLLECTION, + repository = new MongoTicketRepository(TEST_DB, TEST_TICKETS_COLLECTION, TEST_COUNTERS_COLLECTION); } From 3cf2b34d2a1f20a2606d515ad145bf0fb018b44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 14 Sep 2016 22:01:41 +0300 Subject: [PATCH 060/492] Hexagonal pattern: Improve connection properties handling --- .../administration/ConsoleAdministration.java | 2 + .../iluwatar/hexagonal/banking/MongoBank.java | 5 +-- .../database/MongoTicketRepository.java | 5 +-- ...a => MongoConnectionPropertiesLoader.java} | 40 +++++-------------- .../hexagonal/service/ConsoleLottery.java | 2 + .../hexagonal/banking/MongoBankTest.java | 7 ++-- .../database/MongoTicketRepositoryTest.java | 7 ++-- 7 files changed, 25 insertions(+), 43 deletions(-) rename hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/{MongoConnectionProperties.java => MongoConnectionPropertiesLoader.java} (75%) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java index 6a846280c..ea2f33699 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java @@ -28,6 +28,7 @@ import com.iluwatar.hexagonal.domain.LotteryAdministration; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryService; import com.iluwatar.hexagonal.module.LotteryModule; +import com.iluwatar.hexagonal.mongo.MongoConnectionPropertiesLoader; import com.iluwatar.hexagonal.sampledata.SampleData; import java.util.Scanner; @@ -41,6 +42,7 @@ public class ConsoleAdministration { * Program entry point */ public static void main(String[] args) { + MongoConnectionPropertiesLoader.load(); Injector injector = Guice.createInjector(new LotteryModule()); LotteryAdministration administartion = injector.getInstance(LotteryAdministration.class); LotteryService service = injector.getInstance(LotteryService.class); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java index 2a18d8986..23a0e376a 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java @@ -22,7 +22,6 @@ */ package com.iluwatar.hexagonal.banking; -import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -71,8 +70,8 @@ public class MongoBank implements WireTransfers { if (mongoClient != null) { mongoClient.close(); } - MongoConnectionProperties properties = new MongoConnectionProperties().load(); - mongoClient = new MongoClient(properties.getHost(), properties.getPort()); + mongoClient = new MongoClient(System.getProperty("mongo-host"), + Integer.parseInt(System.getProperty("mongo-port"))); database = mongoClient.getDatabase(dbName); accountsCollection = database.getCollection(accountsCollectionName); } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java index 73ff40b78..4cfa83649 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java @@ -26,7 +26,6 @@ import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; -import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -83,8 +82,8 @@ public class MongoTicketRepository implements LotteryTicketRepository { if (mongoClient != null) { mongoClient.close(); } - MongoConnectionProperties properties = new MongoConnectionProperties().load(); - mongoClient = new MongoClient(properties.getHost(), properties.getPort()); + mongoClient = new MongoClient(System.getProperty("mongo-host"), + Integer.parseInt(System.getProperty("mongo-port"))); database = mongoClient.getDatabase(dbName); ticketsCollection = database.getCollection(ticketsCollectionName); countersCollection = database.getCollection(countersCollectionName); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionProperties.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionPropertiesLoader.java similarity index 75% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionProperties.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionPropertiesLoader.java index 20b1876f6..a9bb39803 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionProperties.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/mongo/MongoConnectionPropertiesLoader.java @@ -26,55 +26,33 @@ import java.io.FileInputStream; import java.util.Properties; /** - * Mongo connection properties + * Mongo connection properties loader */ -public class MongoConnectionProperties { +public class MongoConnectionPropertiesLoader { private static final String DEFAULT_HOST = "localhost"; private static final int DEFAULT_PORT = 27017; - private String host; - private int port; - - /** - * Constructor - */ - public MongoConnectionProperties() { - this.host = DEFAULT_HOST; - this.port = DEFAULT_PORT; - } - - /** - * @return host name - */ - public String getHost() { - return host; - } - - /** - * @return port number - */ - public int getPort() { - return port; - } - /** * Try to load connection properties from file. * Fall back to default connection properties. */ - public MongoConnectionProperties load() { + public static void load() { + String host = DEFAULT_HOST; + int port = DEFAULT_PORT; String path = System.getProperty("hexagonal.properties.path"); Properties properties = new Properties(); if (path != null) { try (FileInputStream fin = new FileInputStream(path)) { properties.load(fin); - this.host = properties.getProperty("host"); - this.port = Integer.parseInt(properties.getProperty("port")); + host = properties.getProperty("mongo-host"); + port = Integer.parseInt(properties.getProperty("mongo-port")); } catch (Exception e) { // error occurred, use default properties e.printStackTrace(); } } - return this; + System.setProperty("mongo-host", host); + System.setProperty("mongo-port", String.format("%d", port)); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index afacc35cc..b0d660023 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -32,6 +32,7 @@ import com.iluwatar.hexagonal.domain.LotteryTicketCheckResult; import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; import com.iluwatar.hexagonal.module.LotteryModule; +import com.iluwatar.hexagonal.mongo.MongoConnectionPropertiesLoader; import java.util.HashSet; import java.util.Optional; @@ -48,6 +49,7 @@ public class ConsoleLottery { * Program entry point */ public static void main(String[] args) { + MongoConnectionPropertiesLoader.load(); Injector injector = Guice.createInjector(new LotteryModule()); LotteryService service = injector.getInstance(LotteryService.class); WireTransfers bank = injector.getInstance(WireTransfers.class); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java index 26041b174..ce5c9ff1a 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/banking/MongoBankTest.java @@ -22,7 +22,7 @@ */ package com.iluwatar.hexagonal.banking; -import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; +import com.iluwatar.hexagonal.mongo.MongoConnectionPropertiesLoader; import com.mongodb.MongoClient; import org.junit.Before; import org.junit.Ignore; @@ -43,8 +43,9 @@ public class MongoBankTest { @Before public void init() { - MongoConnectionProperties properties = new MongoConnectionProperties().load(); - MongoClient mongoClient = new MongoClient(properties.getHost(), properties.getPort()); + MongoConnectionPropertiesLoader.load(); + MongoClient mongoClient = new MongoClient(System.getProperty("mongo-host"), + Integer.parseInt(System.getProperty("mongo-port"))); mongoClient.dropDatabase(TEST_DB); mongoClient.close(); mongoBank = new MongoBank(TEST_DB, TEST_ACCOUNTS_COLLECTION); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java index a29b535f6..bbd95b38d 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java @@ -26,7 +26,7 @@ import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryTicket; import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; -import com.iluwatar.hexagonal.mongo.MongoConnectionProperties; +import com.iluwatar.hexagonal.mongo.MongoConnectionPropertiesLoader; import com.mongodb.MongoClient; import org.junit.Before; import org.junit.Ignore; @@ -51,8 +51,9 @@ public class MongoTicketRepositoryTest { @Before public void init() { - MongoConnectionProperties properties = new MongoConnectionProperties().load(); - MongoClient mongoClient = new MongoClient(properties.getHost(), properties.getPort()); + MongoConnectionPropertiesLoader.load(); + MongoClient mongoClient = new MongoClient(System.getProperty("mongo-host"), + Integer.parseInt(System.getProperty("mongo-port"))); mongoClient.dropDatabase(TEST_DB); mongoClient.close(); repository = new MongoTicketRepository(TEST_DB, TEST_TICKETS_COLLECTION, From c4c5e78e50f6ccfe73e5fafaf4019cfb3dc68fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 14 Sep 2016 22:18:42 +0300 Subject: [PATCH 061/492] Hexagonal pattern: Improve error handling in console lottery --- .../hexagonal/service/ConsoleLottery.java | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index b0d660023..eb791ca55 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -79,17 +79,21 @@ public class ConsoleLottery { PlayerDetails details = PlayerDetails.create(email, account, phone); System.out.println("Give 4 comma separated lottery numbers?"); String numbers = readString(scanner); - String[] parts = numbers.split(","); - Set chosen = new HashSet<>(); - for (int i = 0; i < 4; i++) { - chosen.add(Integer.parseInt(parts[i])); - } - LotteryNumbers lotteryNumbers = LotteryNumbers.create(chosen); - LotteryTicket lotteryTicket = LotteryTicket.create(new LotteryTicketId(), details, lotteryNumbers); - Optional id = service.submitTicket(lotteryTicket); - if (id.isPresent()) { - System.out.println("Submitted lottery ticket with id: " + id.get()); - } else { + try { + String[] parts = numbers.split(","); + Set chosen = new HashSet<>(); + for (int i = 0; i < 4; i++) { + chosen.add(Integer.parseInt(parts[i])); + } + LotteryNumbers lotteryNumbers = LotteryNumbers.create(chosen); + LotteryTicket lotteryTicket = LotteryTicket.create(new LotteryTicketId(), details, lotteryNumbers); + Optional id = service.submitTicket(lotteryTicket); + if (id.isPresent()) { + System.out.println("Submitted lottery ticket with id: " + id.get()); + } else { + System.out.println("Failed submitting lottery ticket - please try again."); + } + } catch (Exception e) { System.out.println("Failed submitting lottery ticket - please try again."); } } else if (cmd.equals("4")) { @@ -97,19 +101,23 @@ public class ConsoleLottery { String id = readString(scanner); System.out.println("Give the 4 comma separated winning numbers?"); String numbers = readString(scanner); - String[] parts = numbers.split(","); - Set winningNumbers = new HashSet<>(); - for (int i = 0; i < 4; i++) { - winningNumbers.add(Integer.parseInt(parts[i])); - } - LotteryTicketCheckResult result = service.checkTicketForPrize( - new LotteryTicketId(Integer.parseInt(id)), LotteryNumbers.create(winningNumbers)); - if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { - System.out.println("Congratulations! The lottery ticket has won!"); - } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { - System.out.println("Unfortunately the lottery ticket did not win."); - } else { - System.out.println("Such lottery ticket has not been submitted."); + try { + String[] parts = numbers.split(","); + Set winningNumbers = new HashSet<>(); + for (int i = 0; i < 4; i++) { + winningNumbers.add(Integer.parseInt(parts[i])); + } + LotteryTicketCheckResult result = service.checkTicketForPrize( + new LotteryTicketId(Integer.parseInt(id)), LotteryNumbers.create(winningNumbers)); + if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { + System.out.println("Congratulations! The lottery ticket has won!"); + } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { + System.out.println("Unfortunately the lottery ticket did not win."); + } else { + System.out.println("Such lottery ticket has not been submitted."); + } + } catch (Exception e) { + System.out.println("Failed checking the lottery ticket - please try again."); } } else if (cmd.equals("5")) { exit = true; From df32a7b893fb0120708bfde3d7c0122264033f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Thu, 15 Sep 2016 21:45:09 +0300 Subject: [PATCH 062/492] Hexagonal pattern: Introduced lottery events port with two adapters --- hexagonal/etc/hexagonal.ucls | 4 +- hexagonal/etc/hexagonal.urm.puml | 2 +- .../main/java/com/iluwatar/hexagonal/App.java | 2 +- .../domain/LotteryAdministration.java | 12 +- .../hexagonal/domain/LotteryService.java | 10 +- .../LotteryEventLog.java} | 26 +-- .../hexagonal/eventlog/MongoEventLog.java | 154 ++++++++++++++++++ .../StdOutEventLog.java} | 17 +- .../hexagonal/module/LotteryModule.java | 6 +- .../module/LotteryTestingModule.java | 6 +- .../hexagonal/eventlog/MongoEventLogTest.java | 84 ++++++++++ 11 files changed, 282 insertions(+), 41 deletions(-) rename hexagonal/src/main/java/com/iluwatar/hexagonal/{notifications/LotteryNotifications.java => eventlog/LotteryEventLog.java} (66%) create mode 100644 hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java rename hexagonal/src/main/java/com/iluwatar/hexagonal/{notifications/StdOutNotifications.java => eventlog/StdOutEventLog.java} (83%) create mode 100644 hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java diff --git a/hexagonal/etc/hexagonal.ucls b/hexagonal/etc/hexagonal.ucls index 0318576c2..d3b46b23d 100644 --- a/hexagonal/etc/hexagonal.ucls +++ b/hexagonal/etc/hexagonal.ucls @@ -2,7 +2,7 @@ - @@ -161,7 +161,7 @@ - diff --git a/hexagonal/etc/hexagonal.urm.puml b/hexagonal/etc/hexagonal.urm.puml index 4102c5863..c4b0d0a73 100644 --- a/hexagonal/etc/hexagonal.urm.puml +++ b/hexagonal/etc/hexagonal.urm.puml @@ -116,7 +116,7 @@ package com.iluwatar.hexagonal.database { + save(LotteryTicket) : Optional {abstract} } } -package com.iluwatar.hexagonal.notifications { +package com.iluwatar.hexagonal.eventlog { interface LotteryNotifications { + notifyNoWin(PlayerDetails) {abstract} + notifyPrize(PlayerDetails, int) {abstract} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java index a7d31446b..7ec974c3b 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java @@ -56,7 +56,7 @@ import com.iluwatar.hexagonal.sampledata.SampleData; * * The secondary ports that application core uses are {@link WireTransfers} * which is a banking service, {@link LotteryNotifications} that delivers - * notifications as lottery events occur and {@link LotteryTicketRepository} + * eventlog as lottery events occur and {@link LotteryTicketRepository} * that is the storage for the lottery tickets. * */ diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java index f73390863..3e01b6e03 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java @@ -25,7 +25,7 @@ package com.iluwatar.hexagonal.domain; import com.google.inject.Inject; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.notifications.LotteryNotifications; +import com.iluwatar.hexagonal.eventlog.LotteryEventLog; import java.util.Map; @@ -37,7 +37,7 @@ import java.util.Map; public class LotteryAdministration { private final LotteryTicketRepository repository; - private final LotteryNotifications notifications; + private final LotteryEventLog notifications; private final WireTransfers wireTransfers; private final LotteryTicketChecker checker; @@ -45,7 +45,7 @@ public class LotteryAdministration { * Constructor */ @Inject - public LotteryAdministration(LotteryTicketRepository repository, LotteryNotifications notifications, + public LotteryAdministration(LotteryTicketRepository repository, LotteryEventLog notifications, WireTransfers wireTransfers) { this.repository = repository; this.notifications = notifications; @@ -72,12 +72,12 @@ public class LotteryAdministration { boolean transferred = wireTransfers.transferFunds(LotteryConstants.PRIZE_AMOUNT, LotteryConstants.SERVICE_BANK_ACCOUNT, tickets.get(id).getPlayerDetails().getBankAccount()); if (transferred) { - notifications.notifyPrize(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); + notifications.ticketWon(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); } else { - notifications.notifyPrizeError(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); + notifications.prizeError(tickets.get(id).getPlayerDetails(), LotteryConstants.PRIZE_AMOUNT); } } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { - notifications.notifyNoWin(tickets.get(id).getPlayerDetails()); + notifications.ticketDidNotWin(tickets.get(id).getPlayerDetails()); } } return numbers; diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java index 76cd47d1d..a9dff7fd0 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java @@ -25,7 +25,7 @@ package com.iluwatar.hexagonal.domain; import com.google.inject.Inject; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.notifications.LotteryNotifications; +import com.iluwatar.hexagonal.eventlog.LotteryEventLog; import java.util.Optional; @@ -37,7 +37,7 @@ import java.util.Optional; public class LotteryService { private final LotteryTicketRepository repository; - private final LotteryNotifications notifications; + private final LotteryEventLog notifications; private final WireTransfers wireTransfers; private final LotteryTicketChecker checker; @@ -45,7 +45,7 @@ public class LotteryService { * Constructor */ @Inject - public LotteryService(LotteryTicketRepository repository, LotteryNotifications notifications, + public LotteryService(LotteryTicketRepository repository, LotteryEventLog notifications, WireTransfers wireTransfers) { this.repository = repository; this.notifications = notifications; @@ -60,12 +60,12 @@ public class LotteryService { boolean result = wireTransfers.transferFunds(LotteryConstants.TICKET_PRIZE, ticket.getPlayerDetails().getBankAccount(), LotteryConstants.SERVICE_BANK_ACCOUNT); if (result == false) { - notifications.notifyTicketSubmitError(ticket.getPlayerDetails()); + notifications.ticketSubmitError(ticket.getPlayerDetails()); return Optional.empty(); } Optional optional = repository.save(ticket); if (optional.isPresent()) { - notifications.notifyTicketSubmitted(ticket.getPlayerDetails()); + notifications.ticketSubmitted(ticket.getPlayerDetails()); } return optional; } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/LotteryNotifications.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/LotteryEventLog.java similarity index 66% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/LotteryNotifications.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/LotteryEventLog.java index d7a0cc870..e47640e27 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/LotteryNotifications.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/LotteryEventLog.java @@ -20,40 +20,40 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.hexagonal.notifications; +package com.iluwatar.hexagonal.eventlog; import com.iluwatar.hexagonal.domain.PlayerDetails; /** * - * Provides notifications for lottery events. + * Event log for lottery events * */ -public interface LotteryNotifications { +public interface LotteryEventLog { /** - * Notify lottery ticket was submitted + * lottery ticket submitted */ - void notifyTicketSubmitted(PlayerDetails details); + void ticketSubmitted(PlayerDetails details); /** - * Notify there was an error submitting lottery ticket + * error submitting lottery ticket */ - void notifyTicketSubmitError(PlayerDetails details); + void ticketSubmitError(PlayerDetails details); /** - * Notify lottery ticket did not win + * lottery ticket did not win */ - void notifyNoWin(PlayerDetails details); + void ticketDidNotWin(PlayerDetails details); /** - * Notify that prize has been paid + * lottery ticket won */ - void notifyPrize(PlayerDetails details, int prizeAmount); + void ticketWon(PlayerDetails details, int prizeAmount); /** - * Notify that there was an error paying the prize + * error paying the prize */ - void notifyPrizeError(PlayerDetails details, int prizeAmount); + void prizeError(PlayerDetails details, int prizeAmount); } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java new file mode 100644 index 000000000..7f9b4da5e --- /dev/null +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java @@ -0,0 +1,154 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.eventlog; + +import com.iluwatar.hexagonal.domain.PlayerDetails; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; + +/** + * Mongo based event log + */ +public class MongoEventLog implements LotteryEventLog { + + private static final String DEFAULT_DB = "lotteryDB"; + private static final String DEFAULT_EVENTS_COLLECTION = "events"; + + private MongoClient mongoClient; + private MongoDatabase database; + private MongoCollection eventsCollection; + + private StdOutEventLog stdOutEventLog = new StdOutEventLog(); + + /** + * Constructor + */ + public MongoEventLog() { + connect(); + } + + /** + * Constructor accepting parameters + */ + public MongoEventLog(String dbName, String eventsCollectionName) { + connect(dbName, eventsCollectionName); + } + + /** + * Connect to database with default parameters + */ + public void connect() { + connect(DEFAULT_DB, DEFAULT_EVENTS_COLLECTION); + } + + /** + * Connect to database with given parameters + */ + public void connect(String dbName, String eventsCollectionName) { + if (mongoClient != null) { + mongoClient.close(); + } + mongoClient = new MongoClient(System.getProperty("mongo-host"), + Integer.parseInt(System.getProperty("mongo-port"))); + database = mongoClient.getDatabase(dbName); + eventsCollection = database.getCollection(eventsCollectionName); + } + + /** + * @return mongo client + */ + public MongoClient getMongoClient() { + return mongoClient; + } + + /** + * + * @return mongo database + */ + public MongoDatabase getMongoDatabase() { + return database; + } + + /** + * + * @return accounts collection + */ + public MongoCollection getEventsCollection() { + return eventsCollection; + } + + + @Override + public void ticketSubmitted(PlayerDetails details) { + Document document = new Document("email", details.getEmail()); + document.put("phone", details.getPhoneNumber()); + document.put("bank", details.getBankAccount()); + document.put("message", String.format("Lottery ticket was submitted and bank account was charged for 3 credits.")); + eventsCollection.insertOne(document); + stdOutEventLog.ticketSubmitted(details); + } + + @Override + public void ticketSubmitError(PlayerDetails details) { + Document document = new Document("email", details.getEmail()); + document.put("phone", details.getPhoneNumber()); + document.put("bank", details.getBankAccount()); + document.put("message", String.format("Lottery ticket could not be submitted because lack of funds.")); + eventsCollection.insertOne(document); + stdOutEventLog.ticketSubmitError(details); + } + + @Override + public void ticketDidNotWin(PlayerDetails details) { + Document document = new Document("email", details.getEmail()); + document.put("phone", details.getPhoneNumber()); + document.put("bank", details.getBankAccount()); + document.put("message", String.format("Lottery ticket was checked and unfortunately did not win this time.")); + eventsCollection.insertOne(document); + stdOutEventLog.ticketDidNotWin(details); + } + + @Override + public void ticketWon(PlayerDetails details, int prizeAmount) { + Document document = new Document("email", details.getEmail()); + document.put("phone", details.getPhoneNumber()); + document.put("bank", details.getBankAccount()); + document.put("message", String.format("Lottery ticket won! The bank account was deposited with %d credits.", + prizeAmount)); + eventsCollection.insertOne(document); + stdOutEventLog.ticketWon(details, prizeAmount); + } + + @Override + public void prizeError(PlayerDetails details, int prizeAmount) { + Document document = new Document("email", details.getEmail()); + document.put("phone", details.getPhoneNumber()); + document.put("bank", details.getBankAccount()); + document.put("message", String.format("Lottery ticket won! Unfortunately the bank credit transfer of %d failed.", + prizeAmount)); + eventsCollection.insertOne(document); + stdOutEventLog.prizeError(details, prizeAmount); + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/StdOutNotifications.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/StdOutEventLog.java similarity index 83% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/StdOutNotifications.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/StdOutEventLog.java index f6bd3b546..4150dd401 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/notifications/StdOutNotifications.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/StdOutEventLog.java @@ -20,40 +20,43 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.hexagonal.notifications; +package com.iluwatar.hexagonal.eventlog; import com.iluwatar.hexagonal.domain.PlayerDetails; -public class StdOutNotifications implements LotteryNotifications { +/** + * Standard output event log + */ +public class StdOutEventLog implements LotteryEventLog { @Override - public void notifyTicketSubmitted(PlayerDetails details) { + public void ticketSubmitted(PlayerDetails details) { System.out.println(String.format("Lottery ticket for %s was submitted. Bank account %s was charged for 3 credits.", details.getEmail(), details.getBankAccount())); } @Override - public void notifyNoWin(PlayerDetails details) { + public void ticketDidNotWin(PlayerDetails details) { System.out.println(String.format("Lottery ticket for %s was checked and unfortunately did not win this time.", details.getEmail())); } @Override - public void notifyPrize(PlayerDetails details, int prizeAmount) { + public void ticketWon(PlayerDetails details, int prizeAmount) { System.out .println(String.format("Lottery ticket for %s has won! The bank account %s was deposited with %d credits.", details.getEmail(), details.getBankAccount(), prizeAmount)); } @Override - public void notifyPrizeError(PlayerDetails details, int prizeAmount) { + public void prizeError(PlayerDetails details, int prizeAmount) { System.out .println(String.format("Lottery ticket for %s has won! Unfortunately the bank credit transfer of %d failed.", details.getEmail(), prizeAmount)); } @Override - public void notifyTicketSubmitError(PlayerDetails details) { + public void ticketSubmitError(PlayerDetails details) { System.out.println( String.format("Lottery ticket for %s could not be submitted because the credit transfer of 3 credits failed.", details.getEmail())); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java index c9bc301fc..7e784548d 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryModule.java @@ -27,8 +27,8 @@ import com.iluwatar.hexagonal.banking.MongoBank; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.database.LotteryTicketRepository; import com.iluwatar.hexagonal.database.MongoTicketRepository; -import com.iluwatar.hexagonal.notifications.LotteryNotifications; -import com.iluwatar.hexagonal.notifications.StdOutNotifications; +import com.iluwatar.hexagonal.eventlog.LotteryEventLog; +import com.iluwatar.hexagonal.eventlog.MongoEventLog; /** * Guice module for binding production dependencies @@ -37,7 +37,7 @@ public class LotteryModule extends AbstractModule { @Override protected void configure() { bind(LotteryTicketRepository.class).to(MongoTicketRepository.class); - bind(LotteryNotifications.class).to(StdOutNotifications.class); + bind(LotteryEventLog.class).to(MongoEventLog.class); bind(WireTransfers.class).to(MongoBank.class); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryTestingModule.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryTestingModule.java index c934ed43c..2a1ad1155 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryTestingModule.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/module/LotteryTestingModule.java @@ -27,8 +27,8 @@ import com.iluwatar.hexagonal.banking.InMemoryBank; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.database.InMemoryTicketRepository; import com.iluwatar.hexagonal.database.LotteryTicketRepository; -import com.iluwatar.hexagonal.notifications.LotteryNotifications; -import com.iluwatar.hexagonal.notifications.StdOutNotifications; +import com.iluwatar.hexagonal.eventlog.LotteryEventLog; +import com.iluwatar.hexagonal.eventlog.StdOutEventLog; /** * Guice module for testing dependencies @@ -37,7 +37,7 @@ public class LotteryTestingModule extends AbstractModule { @Override protected void configure() { bind(LotteryTicketRepository.class).to(InMemoryTicketRepository.class); - bind(LotteryNotifications.class).to(StdOutNotifications.class); + bind(LotteryEventLog.class).to(StdOutEventLog.class); bind(WireTransfers.class).to(InMemoryBank.class); } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java new file mode 100644 index 000000000..9b9f14c78 --- /dev/null +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java @@ -0,0 +1,84 @@ +/** + * The MIT License + * Copyright (c) 2014 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.hexagonal.eventlog; + +import com.iluwatar.hexagonal.domain.PlayerDetails; +import com.iluwatar.hexagonal.mongo.MongoConnectionPropertiesLoader; +import com.mongodb.MongoClient; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for Mongo event log + */ +@Ignore +public class MongoEventLogTest { + + private static final String TEST_DB = "lotteryDBTest"; + private static final String TEST_EVENTS_COLLECTION = "testEvents"; + + private MongoEventLog mongoEventLog; + + @Before + public void init() { + MongoConnectionPropertiesLoader.load(); + MongoClient mongoClient = new MongoClient(System.getProperty("mongo-host"), + Integer.parseInt(System.getProperty("mongo-port"))); + mongoClient.dropDatabase(TEST_DB); + mongoClient.close(); + mongoEventLog = new MongoEventLog(TEST_DB, TEST_EVENTS_COLLECTION); + } + + @Test + public void testSetup() { + assertEquals(0, mongoEventLog.getEventsCollection().count()); + } + + @Test + public void testFundTransfers() { + PlayerDetails playerDetails = PlayerDetails.create("john@wayne.com", "000-000", "03432534543"); + mongoEventLog.prizeError(playerDetails, 1000); + assertEquals(1, mongoEventLog.getEventsCollection().count()); + mongoEventLog.prizeError(playerDetails, 1000); + assertEquals(2, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketDidNotWin(playerDetails); + assertEquals(3, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketDidNotWin(playerDetails); + assertEquals(4, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketSubmitError(playerDetails); + assertEquals(5, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketSubmitError(playerDetails); + assertEquals(6, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketSubmitted(playerDetails); + assertEquals(7, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketSubmitted(playerDetails); + assertEquals(8, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketWon(playerDetails, 1000); + assertEquals(9, mongoEventLog.getEventsCollection().count()); + mongoEventLog.ticketWon(playerDetails, 1000); + assertEquals(10, mongoEventLog.getEventsCollection().count()); + } +} From 914d1353a18fbbec8c7036a131f64638da7ebeb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Thu, 15 Sep 2016 21:56:15 +0300 Subject: [PATCH 063/492] Hexagonal pattern: Update test application description --- .../src/main/java/com/iluwatar/hexagonal/App.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java index 7ec974c3b..97190937c 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/App.java @@ -49,13 +49,13 @@ import com.iluwatar.hexagonal.sampledata.SampleData; * The application core is separate from the services that drive it and * from the services it uses.

    * - * The primary ports for the application are {@link LotteryAdministration} - * through which the lottery round is initiated and run and - * {@link LotteryService} that allows players to submit lottery tickets for - * the draw.

    + * The primary ports for the application are console interfaces + * {@link ConsoleAdministration} through which the lottery round is + * initiated and run and {@link ConsoleLottery} that allows players to + * submit lottery tickets for the draw.

    * * The secondary ports that application core uses are {@link WireTransfers} - * which is a banking service, {@link LotteryNotifications} that delivers + * which is a banking service, {@link LotteryEventLog} that delivers * eventlog as lottery events occur and {@link LotteryTicketRepository} * that is the storage for the lottery tickets. * From 6aa58e8ae658cfc66e4421e9b8c92bb017b46906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 17 Sep 2016 09:07:06 +0300 Subject: [PATCH 064/492] Hexagonal pattern: Remove unnecessary factories --- .../database/MongoTicketRepository.java | 4 +- .../domain/LotteryAdministration.java | 4 +- .../hexagonal/domain/LotteryConstants.java | 3 + .../hexagonal/domain/LotteryService.java | 4 +- .../hexagonal/domain/LotteryTicket.java | 9 +-- .../hexagonal/domain/PlayerDetails.java | 11 +-- .../hexagonal/sampledata/SampleData.java | 80 +++++++++---------- .../hexagonal/service/ConsoleLottery.java | 4 +- .../database/MongoTicketRepositoryTest.java | 4 +- .../hexagonal/domain/LotteryTicketTest.java | 12 +-- .../hexagonal/domain/PlayerDetailsTest.java | 6 +- .../hexagonal/eventlog/MongoEventLogTest.java | 2 +- .../hexagonal/test/LotteryTestUtils.java | 4 +- 13 files changed, 66 insertions(+), 81 deletions(-) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java index 4cfa83649..13a937a1b 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java @@ -180,7 +180,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { } private LotteryTicket docToTicket(Document doc) { - PlayerDetails playerDetails = PlayerDetails.create(doc.getString("email"), doc.getString("bank"), + PlayerDetails playerDetails = new PlayerDetails(doc.getString("email"), doc.getString("bank"), doc.getString("phone")); int[] numArray = Arrays.asList(doc.getString("numbers").split(",")).stream().mapToInt(Integer::parseInt).toArray(); HashSet numbers = new HashSet<>(); @@ -188,6 +188,6 @@ public class MongoTicketRepository implements LotteryTicketRepository { numbers.add(num); } LotteryNumbers lotteryNumbers = LotteryNumbers.create(numbers); - return LotteryTicket.create(new LotteryTicketId(doc.getInteger("ticketId")), playerDetails, lotteryNumbers); + return new LotteryTicket(new LotteryTicketId(doc.getInteger("ticketId")), playerDetails, lotteryNumbers); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java index 3e01b6e03..d544c84a1 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java @@ -39,7 +39,6 @@ public class LotteryAdministration { private final LotteryTicketRepository repository; private final LotteryEventLog notifications; private final WireTransfers wireTransfers; - private final LotteryTicketChecker checker; /** * Constructor @@ -50,7 +49,6 @@ public class LotteryAdministration { this.repository = repository; this.notifications = notifications; this.wireTransfers = wireTransfers; - this.checker = new LotteryTicketChecker(this.repository); } /** @@ -67,7 +65,7 @@ public class LotteryAdministration { LotteryNumbers numbers = LotteryNumbers.createRandom(); Map tickets = getAllSubmittedTickets(); for (LotteryTicketId id : tickets.keySet()) { - LotteryTicketCheckResult result = checker.checkTicketForPrize(id, numbers); + LotteryTicketCheckResult result = new LotteryTicketChecker(repository).checkTicketForPrize(id, numbers); if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { boolean transferred = wireTransfers.transferFunds(LotteryConstants.PRIZE_AMOUNT, LotteryConstants.SERVICE_BANK_ACCOUNT, tickets.get(id).getPlayerDetails().getBankAccount()); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryConstants.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryConstants.java index fb4c8025f..28fd4e2f4 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryConstants.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryConstants.java @@ -29,6 +29,9 @@ package com.iluwatar.hexagonal.domain; */ public class LotteryConstants { + private LotteryConstants() { + } + public static final int PRIZE_AMOUNT = 100000; public static final String SERVICE_BANK_ACCOUNT = "123-123"; public static final int TICKET_PRIZE = 3; diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java index a9dff7fd0..6a032462d 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java @@ -39,7 +39,6 @@ public class LotteryService { private final LotteryTicketRepository repository; private final LotteryEventLog notifications; private final WireTransfers wireTransfers; - private final LotteryTicketChecker checker; /** * Constructor @@ -50,7 +49,6 @@ public class LotteryService { this.repository = repository; this.notifications = notifications; this.wireTransfers = wireTransfers; - this.checker = new LotteryTicketChecker(this.repository); } /** @@ -74,6 +72,6 @@ public class LotteryService { * Check if lottery ticket has won */ public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { - return checker.checkTicketForPrize(id, winningNumbers); + return new LotteryTicketChecker(repository).checkTicketForPrize(id, winningNumbers); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java index 3e9ebdae4..9fa318e4c 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicket.java @@ -36,19 +36,12 @@ public class LotteryTicket { /** * Constructor. */ - private LotteryTicket(LotteryTicketId id, PlayerDetails details, LotteryNumbers numbers) { + public LotteryTicket(LotteryTicketId id, PlayerDetails details, LotteryNumbers numbers) { this.id = id; playerDetails = details; lotteryNumbers = numbers; } - /** - * Factory for creating lottery tickets; - */ - public static LotteryTicket create(LotteryTicketId id, PlayerDetails details, LotteryNumbers numbers) { - return new LotteryTicket(id, details, numbers); - } - /** * @return player details */ diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java index 1061ad553..7af115a7c 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/PlayerDetails.java @@ -36,19 +36,12 @@ public class PlayerDetails { /** * Constructor. */ - private PlayerDetails(String email, String bankAccount, String phone) { + public PlayerDetails(String email, String bankAccount, String phone) { emailAddress = email; bankAccountNumber = bankAccount; phoneNumber = phone; } - - /** - * Factory for creating new objects. - */ - public static PlayerDetails create(String email, String bankAccount, String phone) { - return new PlayerDetails(email, bankAccount, phone); - } - + /** * @return email */ diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java index b9c779c34..13458d02a 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/sampledata/SampleData.java @@ -43,45 +43,45 @@ public class SampleData { static { PLAYERS = new ArrayList<>(); - PLAYERS.add(PlayerDetails.create("john@google.com", "312-342", "+3242434242")); - PLAYERS.add(PlayerDetails.create("mary@google.com", "234-987", "+23452346")); - PLAYERS.add(PlayerDetails.create("steve@google.com", "833-836", "+63457543")); - PLAYERS.add(PlayerDetails.create("wayne@google.com", "319-826", "+24626")); - PLAYERS.add(PlayerDetails.create("johnie@google.com", "983-322", "+3635635")); - PLAYERS.add(PlayerDetails.create("andy@google.com", "934-734", "+0898245")); - PLAYERS.add(PlayerDetails.create("richard@google.com", "536-738", "+09845325")); - PLAYERS.add(PlayerDetails.create("kevin@google.com", "453-936", "+2423532")); - PLAYERS.add(PlayerDetails.create("arnold@google.com", "114-988", "+5646346524")); - PLAYERS.add(PlayerDetails.create("ian@google.com", "663-765", "+928394235")); - PLAYERS.add(PlayerDetails.create("robin@google.com", "334-763", "+35448")); - PLAYERS.add(PlayerDetails.create("ted@google.com", "735-964", "+98752345")); - PLAYERS.add(PlayerDetails.create("larry@google.com", "734-853", "+043842423")); - PLAYERS.add(PlayerDetails.create("calvin@google.com", "334-746", "+73294135")); - PLAYERS.add(PlayerDetails.create("jacob@google.com", "444-766", "+358042354")); - PLAYERS.add(PlayerDetails.create("edwin@google.com", "895-345", "+9752435")); - PLAYERS.add(PlayerDetails.create("mary@google.com", "760-009", "+34203542")); - PLAYERS.add(PlayerDetails.create("lolita@google.com", "425-907", "+9872342")); - PLAYERS.add(PlayerDetails.create("bruno@google.com", "023-638", "+673824122")); - PLAYERS.add(PlayerDetails.create("peter@google.com", "335-886", "+5432503945")); - PLAYERS.add(PlayerDetails.create("warren@google.com", "225-946", "+9872341324")); - PLAYERS.add(PlayerDetails.create("monica@google.com", "265-748", "+134124")); - PLAYERS.add(PlayerDetails.create("ollie@google.com", "190-045", "+34453452")); - PLAYERS.add(PlayerDetails.create("yngwie@google.com", "241-465", "+9897641231")); - PLAYERS.add(PlayerDetails.create("lars@google.com", "746-936", "+42345298345")); - PLAYERS.add(PlayerDetails.create("bobbie@google.com", "946-384", "+79831742")); - PLAYERS.add(PlayerDetails.create("tyron@google.com", "310-992", "+0498837412")); - PLAYERS.add(PlayerDetails.create("tyrell@google.com", "032-045", "+67834134")); - PLAYERS.add(PlayerDetails.create("nadja@google.com", "000-346", "+498723")); - PLAYERS.add(PlayerDetails.create("wendy@google.com", "994-989", "+987324454")); - PLAYERS.add(PlayerDetails.create("luke@google.com", "546-634", "+987642435")); - PLAYERS.add(PlayerDetails.create("bjorn@google.com", "342-874", "+7834325")); - PLAYERS.add(PlayerDetails.create("lisa@google.com", "024-653", "+980742154")); - PLAYERS.add(PlayerDetails.create("anton@google.com", "834-935", "+876423145")); - PLAYERS.add(PlayerDetails.create("bruce@google.com", "284-936", "+09843212345")); - PLAYERS.add(PlayerDetails.create("ray@google.com", "843-073", "+678324123")); - PLAYERS.add(PlayerDetails.create("ron@google.com", "637-738", "+09842354")); - PLAYERS.add(PlayerDetails.create("xavier@google.com", "143-947", "+375245")); - PLAYERS.add(PlayerDetails.create("harriet@google.com", "842-404", "+131243252")); + PLAYERS.add(new PlayerDetails("john@google.com", "312-342", "+3242434242")); + PLAYERS.add(new PlayerDetails("mary@google.com", "234-987", "+23452346")); + PLAYERS.add(new PlayerDetails("steve@google.com", "833-836", "+63457543")); + PLAYERS.add(new PlayerDetails("wayne@google.com", "319-826", "+24626")); + PLAYERS.add(new PlayerDetails("johnie@google.com", "983-322", "+3635635")); + PLAYERS.add(new PlayerDetails("andy@google.com", "934-734", "+0898245")); + PLAYERS.add(new PlayerDetails("richard@google.com", "536-738", "+09845325")); + PLAYERS.add(new PlayerDetails("kevin@google.com", "453-936", "+2423532")); + PLAYERS.add(new PlayerDetails("arnold@google.com", "114-988", "+5646346524")); + PLAYERS.add(new PlayerDetails("ian@google.com", "663-765", "+928394235")); + PLAYERS.add(new PlayerDetails("robin@google.com", "334-763", "+35448")); + PLAYERS.add(new PlayerDetails("ted@google.com", "735-964", "+98752345")); + PLAYERS.add(new PlayerDetails("larry@google.com", "734-853", "+043842423")); + PLAYERS.add(new PlayerDetails("calvin@google.com", "334-746", "+73294135")); + PLAYERS.add(new PlayerDetails("jacob@google.com", "444-766", "+358042354")); + PLAYERS.add(new PlayerDetails("edwin@google.com", "895-345", "+9752435")); + PLAYERS.add(new PlayerDetails("mary@google.com", "760-009", "+34203542")); + PLAYERS.add(new PlayerDetails("lolita@google.com", "425-907", "+9872342")); + PLAYERS.add(new PlayerDetails("bruno@google.com", "023-638", "+673824122")); + PLAYERS.add(new PlayerDetails("peter@google.com", "335-886", "+5432503945")); + PLAYERS.add(new PlayerDetails("warren@google.com", "225-946", "+9872341324")); + PLAYERS.add(new PlayerDetails("monica@google.com", "265-748", "+134124")); + PLAYERS.add(new PlayerDetails("ollie@google.com", "190-045", "+34453452")); + PLAYERS.add(new PlayerDetails("yngwie@google.com", "241-465", "+9897641231")); + PLAYERS.add(new PlayerDetails("lars@google.com", "746-936", "+42345298345")); + PLAYERS.add(new PlayerDetails("bobbie@google.com", "946-384", "+79831742")); + PLAYERS.add(new PlayerDetails("tyron@google.com", "310-992", "+0498837412")); + PLAYERS.add(new PlayerDetails("tyrell@google.com", "032-045", "+67834134")); + PLAYERS.add(new PlayerDetails("nadja@google.com", "000-346", "+498723")); + PLAYERS.add(new PlayerDetails("wendy@google.com", "994-989", "+987324454")); + PLAYERS.add(new PlayerDetails("luke@google.com", "546-634", "+987642435")); + PLAYERS.add(new PlayerDetails("bjorn@google.com", "342-874", "+7834325")); + PLAYERS.add(new PlayerDetails("lisa@google.com", "024-653", "+980742154")); + PLAYERS.add(new PlayerDetails("anton@google.com", "834-935", "+876423145")); + PLAYERS.add(new PlayerDetails("bruce@google.com", "284-936", "+09843212345")); + PLAYERS.add(new PlayerDetails("ray@google.com", "843-073", "+678324123")); + PLAYERS.add(new PlayerDetails("ron@google.com", "637-738", "+09842354")); + PLAYERS.add(new PlayerDetails("xavier@google.com", "143-947", "+375245")); + PLAYERS.add(new PlayerDetails("harriet@google.com", "842-404", "+131243252")); InMemoryBank wireTransfers = new InMemoryBank(); Random random = new Random(); for (int i = 0; i < PLAYERS.size(); i++) { @@ -95,7 +95,7 @@ public class SampleData { */ public static void submitTickets(LotteryService lotteryService, int numTickets) { for (int i = 0; i < numTickets; i++) { - LotteryTicket ticket = LotteryTicket.create(new LotteryTicketId(), + LotteryTicket ticket = new LotteryTicket(new LotteryTicketId(), getRandomPlayerDetails(), LotteryNumbers.createRandom()); lotteryService.submitTicket(ticket); } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index eb791ca55..cc13d389d 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -76,7 +76,7 @@ public class ConsoleLottery { String account = readString(scanner); System.out.println("What is your phone number?"); String phone = readString(scanner); - PlayerDetails details = PlayerDetails.create(email, account, phone); + PlayerDetails details = new PlayerDetails(email, account, phone); System.out.println("Give 4 comma separated lottery numbers?"); String numbers = readString(scanner); try { @@ -86,7 +86,7 @@ public class ConsoleLottery { chosen.add(Integer.parseInt(parts[i])); } LotteryNumbers lotteryNumbers = LotteryNumbers.create(chosen); - LotteryTicket lotteryTicket = LotteryTicket.create(new LotteryTicketId(), details, lotteryNumbers); + LotteryTicket lotteryTicket = new LotteryTicket(new LotteryTicketId(), details, lotteryNumbers); Optional id = service.submitTicket(lotteryTicket); if (id.isPresent()) { System.out.println("Submitted lottery ticket with id: " + id.get()); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java index bbd95b38d..e30468f99 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/database/MongoTicketRepositoryTest.java @@ -76,9 +76,9 @@ public class MongoTicketRepositoryTest { @Test public void testCrudOperations() { // create new lottery ticket and save it - PlayerDetails details = PlayerDetails.create("foo@bar.com", "123-123", "07001234"); + PlayerDetails details = new PlayerDetails("foo@bar.com", "123-123", "07001234"); LotteryNumbers random = LotteryNumbers.createRandom(); - LotteryTicket original = LotteryTicket.create(new LotteryTicketId(), details, random); + LotteryTicket original = new LotteryTicket(new LotteryTicketId(), details, random); Optional saved = repository.save(original); assertEquals(1, repository.getTicketsCollection().count()); assertTrue(saved.isPresent()); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java index 4840dc897..ce1e6b4b0 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java @@ -34,16 +34,16 @@ public class LotteryTicketTest { @Test public void testEquals() { - PlayerDetails details1 = PlayerDetails.create("bob@foo.bar", "1212-121212", "+34332322"); + PlayerDetails details1 = new PlayerDetails("bob@foo.bar", "1212-121212", "+34332322"); LotteryNumbers numbers1 = LotteryNumbers.create(new HashSet(Arrays.asList(1, 2, 3, 4))); - LotteryTicket ticket1 = LotteryTicket.create(new LotteryTicketId(), details1, numbers1); - PlayerDetails details2 = PlayerDetails.create("bob@foo.bar", "1212-121212", "+34332322"); + LotteryTicket ticket1 = new LotteryTicket(new LotteryTicketId(), details1, numbers1); + PlayerDetails details2 = new PlayerDetails("bob@foo.bar", "1212-121212", "+34332322"); LotteryNumbers numbers2 = LotteryNumbers.create(new HashSet(Arrays.asList(1, 2, 3, 4))); - LotteryTicket ticket2 = LotteryTicket.create(new LotteryTicketId(), details2, numbers2); + LotteryTicket ticket2 = new LotteryTicket(new LotteryTicketId(), details2, numbers2); assertEquals(ticket1, ticket2); - PlayerDetails details3 = PlayerDetails.create("elsa@foo.bar", "1223-121212", "+49332322"); + PlayerDetails details3 = new PlayerDetails("elsa@foo.bar", "1223-121212", "+49332322"); LotteryNumbers numbers3 = LotteryNumbers.create(new HashSet(Arrays.asList(1, 2, 3, 8))); - LotteryTicket ticket3 = LotteryTicket.create(new LotteryTicketId(), details3, numbers3); + LotteryTicket ticket3 = new LotteryTicket(new LotteryTicketId(), details3, numbers3); assertFalse(ticket1.equals(ticket3)); } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/PlayerDetailsTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/PlayerDetailsTest.java index 813b035a2..53aa2d9d5 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/PlayerDetailsTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/PlayerDetailsTest.java @@ -36,10 +36,10 @@ public class PlayerDetailsTest { @Test public void testEquals() { - PlayerDetails details1 = PlayerDetails.create("tom@foo.bar", "11212-123434", "+12323425"); - PlayerDetails details2 = PlayerDetails.create("tom@foo.bar", "11212-123434", "+12323425"); + PlayerDetails details1 = new PlayerDetails("tom@foo.bar", "11212-123434", "+12323425"); + PlayerDetails details2 = new PlayerDetails("tom@foo.bar", "11212-123434", "+12323425"); assertEquals(details1, details2); - PlayerDetails details3 = PlayerDetails.create("john@foo.bar", "16412-123439", "+34323432"); + PlayerDetails details3 = new PlayerDetails("john@foo.bar", "16412-123439", "+34323432"); assertFalse(details1.equals(details3)); } } diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java index 9b9f14c78..d02694826 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/eventlog/MongoEventLogTest.java @@ -59,7 +59,7 @@ public class MongoEventLogTest { @Test public void testFundTransfers() { - PlayerDetails playerDetails = PlayerDetails.create("john@wayne.com", "000-000", "03432534543"); + PlayerDetails playerDetails = new PlayerDetails("john@wayne.com", "000-000", "03432534543"); mongoEventLog.prizeError(playerDetails, 1000); assertEquals(1, mongoEventLog.getEventsCollection().count()); mongoEventLog.prizeError(playerDetails, 1000); diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java index 02304296f..ae15cd3d7 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/test/LotteryTestUtils.java @@ -50,8 +50,8 @@ public class LotteryTestUtils { */ public static LotteryTicket createLotteryTicket(String email, String account, String phone, Set givenNumbers) { - PlayerDetails details = PlayerDetails.create(email, account, phone); + PlayerDetails details = new PlayerDetails(email, account, phone); LotteryNumbers numbers = LotteryNumbers.create(givenNumbers); - return LotteryTicket.create(new LotteryTicketId(), details, numbers); + return new LotteryTicket(new LotteryTicketId(), details, numbers); } } From b030cd4ebafcdcb017cbec979ec58b0de663ceba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 17 Sep 2016 09:20:33 +0300 Subject: [PATCH 065/492] Hexagonal pattern: Introduce lottery utils class --- .../hexagonal/domain/LotteryAdministration.java | 2 +- .../iluwatar/hexagonal/domain/LotteryService.java | 2 +- ...LotteryTicketChecker.java => LotteryUtils.java} | 14 ++++++-------- 3 files changed, 8 insertions(+), 10 deletions(-) rename hexagonal/src/main/java/com/iluwatar/hexagonal/domain/{LotteryTicketChecker.java => LotteryUtils.java} (83%) diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java index d544c84a1..bc264a9ef 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryAdministration.java @@ -65,7 +65,7 @@ public class LotteryAdministration { LotteryNumbers numbers = LotteryNumbers.createRandom(); Map tickets = getAllSubmittedTickets(); for (LotteryTicketId id : tickets.keySet()) { - LotteryTicketCheckResult result = new LotteryTicketChecker(repository).checkTicketForPrize(id, numbers); + LotteryTicketCheckResult result = LotteryUtils.checkTicketForPrize(repository, id, numbers); if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { boolean transferred = wireTransfers.transferFunds(LotteryConstants.PRIZE_AMOUNT, LotteryConstants.SERVICE_BANK_ACCOUNT, tickets.get(id).getPlayerDetails().getBankAccount()); diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java index 6a032462d..dceac26e4 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryService.java @@ -72,6 +72,6 @@ public class LotteryService { * Check if lottery ticket has won */ public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { - return new LotteryTicketChecker(repository).checkTicketForPrize(id, winningNumbers); + return LotteryUtils.checkTicketForPrize(repository, id, winningNumbers); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryUtils.java similarity index 83% rename from hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java rename to hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryUtils.java index ce193386b..dc34c7f7d 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketChecker.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryUtils.java @@ -27,20 +27,18 @@ import com.iluwatar.hexagonal.database.LotteryTicketRepository; import java.util.Optional; /** - * Lottery ticket checker + * Lottery utilities */ -public class LotteryTicketChecker { +public class LotteryUtils { - private final LotteryTicketRepository repository; - - public LotteryTicketChecker(LotteryTicketRepository repository) { - this.repository = repository; + private LotteryUtils() { } /** - * Check if lottery ticket has won + * Checks if lottery ticket has won */ - public LotteryTicketCheckResult checkTicketForPrize(LotteryTicketId id, LotteryNumbers winningNumbers) { + public static LotteryTicketCheckResult checkTicketForPrize(LotteryTicketRepository repository, LotteryTicketId id, + LotteryNumbers winningNumbers) { Optional optional = repository.findById(id); if (optional.isPresent()) { if (optional.get().getNumbers().equals(winningNumbers)) { From 6026eedd51b9753250051b620312bbedd2ccd6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 18 Sep 2016 17:51:09 +0300 Subject: [PATCH 066/492] UML generation: Mark the urm-maven-plugin execution to be ignored in Eclipse and recreate all .puml files --- .../etc/abstract-document.urm.puml | 36 +-- .../etc/abstract-factory.urm.puml | 94 +++---- adapter/etc/adapter.urm.puml | 22 +- .../etc/aggregator-service.urm.puml | 42 +-- .../etc/inventory-microservice.urm.puml | 8 +- api-gateway/etc/api-gateway-service.urm.puml | 28 +- .../etc/async-method-invocation.urm.puml | 26 +- bridge/etc/bridge.urm.puml | 64 ++--- builder/etc/builder.urm.puml | 90 +++--- .../etc/business-delegate.urm.puml | 22 +- caching/etc/caching.urm.puml | 50 ++-- callback/etc/callback.urm.puml | 26 +- chain/etc/chain.urm.puml | 40 +-- command/etc/command.urm.puml | 68 ++--- composite/etc/composite.urm.puml | 30 +- dao/etc/dao.urm.puml | 90 +++--- decorator/etc/decorator.urm.puml | 10 +- delegation/etc/delegation.urm.puml | 20 +- .../etc/dependency-injection.urm.puml | 56 ++-- double-dispatch/etc/double-dispatch.urm.puml | 28 +- .../etc/event-aggregator.urm.puml | 54 ++-- .../etc/event-driven-architecture.urm.puml | 30 +- execute-around/etc/execute-around.urm.puml | 6 +- facade/etc/facade.urm.puml | 18 +- factory-kit/etc/factory-kit.urm.puml | 36 +-- factory-method/etc/factory-method.urm.puml | 6 +- feature-toggle/etc/feature-toggle.urm.puml | 16 +- fluentinterface/etc/fluentinterface.urm.puml | 16 +- flux/etc/flux.urm.puml | 88 +++--- flyweight/etc/flyweight.urm.puml | 46 +-- .../etc/front-controller.urm.puml | 46 +-- .../etc/half-sync-half-async.urm.puml | 26 +- hexagonal/etc/hexagonal.urm.puml | 265 ++++++++++++------ .../etc/intercepting-filter.urm.puml | 72 ++--- interpreter/etc/interpreter.urm.puml | 54 ++-- iterator/etc/iterator.urm.puml | 22 +- layers/etc/layers.urm.puml | 172 ++++++------ lazy-loading/etc/lazy-loading.urm.puml | 20 +- mediator/etc/mediator.urm.puml | 38 +-- memento/etc/memento.urm.puml | 24 +- .../etc/model-view-controller.urm.puml | 34 +-- .../etc/model-view-presenter.urm.puml | 78 +++--- monostate/etc/monostate.urm.puml | 16 +- mute-idiom/etc/mute-idiom.urm.puml | 6 +- mutex/etc/mutex.urm.puml | 12 +- naked-objects/etc/naked-objects-dom.urm.puml | 47 +--- .../etc/naked-objects-fixture.urm.puml | 10 +- .../etc/naked-objects-integtests.urm.puml | 26 +- null-object/etc/null-object.urm.puml | 36 +-- object-pool/etc/object-pool.urm.puml | 16 +- observer/etc/observer.urm.puml | 36 +-- poison-pill/etc/poison-pill.urm.puml | 46 +-- pom.xml | 19 ++ .../etc/private-class-data.urm.puml | 26 +- .../etc/producer-consumer.urm.puml | 34 +-- promise/etc/promise.urm.puml | 36 +-- property/etc/property.urm.puml | 32 +-- prototype/etc/prototype.urm.puml | 76 ++--- proxy/etc/proxy.urm.puml | 12 +- reactor/etc/reactor.urm.puml | 140 ++++----- .../etc/reader-writer-lock.urm.puml | 36 +-- repository/etc/repository.urm.puml | 50 ++-- ...rce-acquisition-is-initialization.urm.puml | 8 +- semaphore/etc/semaphore.urm.puml | 42 +-- servant/etc/servant.urm.puml | 40 +-- service-layer/etc/service-layer.urm.puml | 76 ++--- service-locator/etc/service-locator.urm.puml | 30 +- singleton/etc/singleton.urm.puml | 22 +- specification/etc/specification.urm.puml | 66 ++--- state/etc/state.urm.puml | 32 +-- step-builder/etc/step-builder.urm.puml | 36 +-- strategy/etc/strategy.urm.puml | 26 +- template-method/etc/template-method.urm.puml | 26 +- thread-pool/etc/thread-pool.urm.puml | 30 +- tolerant-reader/etc/tolerant-reader.urm.puml | 18 +- twin/etc/twin.urm.puml | 18 +- value-object/etc/value-object.urm.puml | 8 +- visitor/etc/visitor.urm.puml | 78 +++--- 78 files changed, 1676 insertions(+), 1609 deletions(-) diff --git a/abstract-document/etc/abstract-document.urm.puml b/abstract-document/etc/abstract-document.urm.puml index c738b50ce..fa15eb3c7 100644 --- a/abstract-document/etc/abstract-document.urm.puml +++ b/abstract-document/etc/abstract-document.urm.puml @@ -3,31 +3,30 @@ package com.iluwatar.abstractdocument.domain { class Part { + Part(properties : Map) } - class Car { - + Car(properties : Map) - } - interface HasModel { + interface HasPrice { + PROPERTY : String {static} - + getModel() : Optional + + getPrice() : Optional } interface HasParts { + PROPERTY : String {static} + getParts() : Stream } + class Car { + + Car(properties : Map) + } interface HasType { + PROPERTY : String {static} + getType() : Optional } - interface HasPrice { + interface HasModel { + PROPERTY : String {static} - + getPrice() : Optional + + getModel() : Optional } } package com.iluwatar.abstractdocument { - interface Document { - + children(String, Function, T>) : Stream {abstract} - + get(String) : Object {abstract} - + put(String, Object) {abstract} + class App { + + App() + + main(args : String[]) {static} } abstract class AbstractDocument { - properties : Map @@ -37,9 +36,10 @@ package com.iluwatar.abstractdocument { + put(key : String, value : Object) + toString() : String } - class App { - + App() - + main(args : String[]) {static} + interface Document { + + children(String, Function, T>) : Stream {abstract} + + get(String) : Object {abstract} + + put(String, Object) {abstract} } } AbstractDocument --+ Map @@ -47,13 +47,13 @@ Part ..|> HasType Part ..|> HasModel Part ..|> HasPrice Part --|> AbstractDocument +AbstractDocument ..|> Document +HasPrice --|> Document +HasParts --|> Document Car ..|> HasModel Car ..|> HasPrice Car ..|> HasParts Car --|> AbstractDocument -HasModel --|> Document -HasParts --|> Document -AbstractDocument ..|> Document HasType --|> Document -HasPrice --|> Document +HasModel --|> Document @enduml \ No newline at end of file diff --git a/abstract-factory/etc/abstract-factory.urm.puml b/abstract-factory/etc/abstract-factory.urm.puml index 88402c6d7..9648a6a96 100644 --- a/abstract-factory/etc/abstract-factory.urm.puml +++ b/abstract-factory/etc/abstract-factory.urm.puml @@ -1,22 +1,5 @@ @startuml package com.iluwatar.abstractfactory { - interface Castle { - + getDescription() : String {abstract} - } - class OrcKingdomFactory { - + OrcKingdomFactory() - + createArmy() : Army - + createCastle() : Castle - + createKing() : King - } - class ElfKing { - ~ DESCRIPTION : String {static} - + ElfKing() - + getDescription() : String - } - interface King { - + getDescription() : String {abstract} - } class App { - army : Army - castle : Castle @@ -34,35 +17,12 @@ package com.iluwatar.abstractfactory { - setCastle(castle : Castle) - setKing(king : King) } - class OrcKing { - ~ DESCRIPTION : String {static} - + OrcKing() - + getDescription() : String - } - class ElfKingdomFactory { - + ElfKingdomFactory() + class OrcKingdomFactory { + + OrcKingdomFactory() + createArmy() : Army + createCastle() : Castle + createKing() : King } - interface Army { - + getDescription() : String {abstract} - } - class OrcArmy { - ~ DESCRIPTION : String {static} - + OrcArmy() - + getDescription() : String - } - interface KingdomFactory { - + createArmy() : Army {abstract} - + createCastle() : Castle {abstract} - + createKing() : King {abstract} - } - class ElfArmy { - ~ DESCRIPTION : String {static} - + ElfArmy() - + getDescription() : String - } class ElfCastle { ~ DESCRIPTION : String {static} + ElfCastle() @@ -73,16 +33,56 @@ package com.iluwatar.abstractfactory { + OrcCastle() + getDescription() : String } + interface KingdomFactory { + + createArmy() : Army {abstract} + + createCastle() : Castle {abstract} + + createKing() : King {abstract} + } + class ElfKing { + ~ DESCRIPTION : String {static} + + ElfKing() + + getDescription() : String + } + class ElfArmy { + ~ DESCRIPTION : String {static} + + ElfArmy() + + getDescription() : String + } + interface Castle { + + getDescription() : String {abstract} + } + interface Army { + + getDescription() : String {abstract} + } + class OrcKing { + ~ DESCRIPTION : String {static} + + OrcKing() + + getDescription() : String + } + class OrcArmy { + ~ DESCRIPTION : String {static} + + OrcArmy() + + getDescription() : String + } + interface King { + + getDescription() : String {abstract} + } + class ElfKingdomFactory { + + ElfKingdomFactory() + + createArmy() : Army + + createCastle() : Castle + + createKing() : King + } } App --> "-castle" Castle App --> "-king" King App --> "-army" Army OrcKingdomFactory ..|> KingdomFactory -ElfKing ..|> King -OrcKing ..|> King -ElfKingdomFactory ..|> KingdomFactory -OrcArmy ..|> Army -ElfArmy ..|> Army ElfCastle ..|> Castle OrcCastle ..|> Castle +ElfKing ..|> King +ElfArmy ..|> Army +OrcKing ..|> King +OrcArmy ..|> Army +ElfKingdomFactory ..|> KingdomFactory @enduml \ No newline at end of file diff --git a/adapter/etc/adapter.urm.puml b/adapter/etc/adapter.urm.puml index 2cee13dc4..a7c962a3b 100644 --- a/adapter/etc/adapter.urm.puml +++ b/adapter/etc/adapter.urm.puml @@ -1,13 +1,19 @@ @startuml package com.iluwatar.adapter { - class App { - + App() - + main(args : String[]) {static} - } interface BattleShip { + fire() {abstract} + move() {abstract} } + class BattleFishingBoat { + - boat : FishingBoat + + BattleFishingBoat() + + fire() + + move() + } + class App { + + App() + + main(args : String[]) {static} + } class Captain { - battleship : BattleShip + Captain() @@ -16,12 +22,6 @@ package com.iluwatar.adapter { + move() + setBattleship(battleship : BattleShip) } - class BattleFishingBoat { - - boat : FishingBoat - + BattleFishingBoat() - + fire() - + move() - } class FishingBoat { + FishingBoat() + fish() @@ -30,6 +30,6 @@ package com.iluwatar.adapter { } BattleFishingBoat --> "-boat" FishingBoat Captain --> "-battleship" BattleShip -Captain ..|> BattleShip BattleFishingBoat ..|> BattleShip +Captain ..|> BattleShip @enduml \ No newline at end of file diff --git a/aggregator-microservices/etc/aggregator-service.urm.puml b/aggregator-microservices/etc/aggregator-service.urm.puml index 5c2e1167a..2a6600531 100644 --- a/aggregator-microservices/etc/aggregator-service.urm.puml +++ b/aggregator-microservices/etc/aggregator-service.urm.puml @@ -1,5 +1,25 @@ @startuml package com.iluwatar.aggregator.microservices { + class ProductInventoryClientImpl { + + ProductInventoryClientImpl() + + getProductInventories() : int + } + class App { + + App() + + main(args : String[]) {static} + } + interface ProductInventoryClient { + + getProductInventories() : int {abstract} + } + class Product { + - productInventories : int + - title : String + + Product() + + getProductInventories() : int + + getTitle() : String + + setProductInventories(productInventories : int) + + setTitle(title : String) + } class Aggregator { - informationClient : ProductInformationClient - inventoryClient : ProductInventoryClient @@ -13,29 +33,9 @@ package com.iluwatar.aggregator.microservices { interface ProductInformationClient { + getProductTitle() : String {abstract} } - class Product { - - productInventories : int - - title : String - + Product() - + getProductInventories() : int - + getTitle() : String - + setProductInventories(productInventories : int) - + setTitle(title : String) - } - class ProductInventoryClientImpl { - + ProductInventoryClientImpl() - + getProductInventories() : int - } - class App { - + App() - + main(args : String[]) {static} - } - interface ProductInventoryClient { - + getProductInventories() : int {abstract} - } } Aggregator --> "-inventoryClient" ProductInventoryClient Aggregator --> "-informationClient" ProductInformationClient -ProductInformationClientImpl ..|> ProductInformationClient ProductInventoryClientImpl ..|> ProductInventoryClient +ProductInformationClientImpl ..|> ProductInformationClient @enduml \ No newline at end of file diff --git a/aggregator-microservices/etc/inventory-microservice.urm.puml b/aggregator-microservices/etc/inventory-microservice.urm.puml index 90f327e07..a07a36306 100644 --- a/aggregator-microservices/etc/inventory-microservice.urm.puml +++ b/aggregator-microservices/etc/inventory-microservice.urm.puml @@ -1,12 +1,12 @@ @startuml package com.iluwatar.inventory.microservice { - class InventoryApplication { - + InventoryApplication() - + main(args : String[]) {static} - } class InventoryController { + InventoryController() + getProductInventories() : int } + class InventoryApplication { + + InventoryApplication() + + main(args : String[]) {static} + } } @enduml \ No newline at end of file diff --git a/api-gateway/etc/api-gateway-service.urm.puml b/api-gateway/etc/api-gateway-service.urm.puml index 3313f7059..409e7ee91 100644 --- a/api-gateway/etc/api-gateway-service.urm.puml +++ b/api-gateway/etc/api-gateway-service.urm.puml @@ -1,7 +1,16 @@ @startuml package com.iluwatar.api.gateway { - interface ImageClient { - + getImagePath() : String {abstract} + class App { + + App() + + main(args : String[]) {static} + } + class PriceClientImpl { + + PriceClientImpl() + + getPrice() : String + } + class ImageClientImpl { + + ImageClientImpl() + + getImagePath() : String } class MobileProduct { - price : String @@ -9,6 +18,9 @@ package com.iluwatar.api.gateway { + getPrice() : String + setPrice(price : String) } + interface ImageClient { + + getImagePath() : String {abstract} + } class ApiGateway { - imageClient : ImageClient - priceClient : PriceClient @@ -28,18 +40,6 @@ package com.iluwatar.api.gateway { interface PriceClient { + getPrice() : String {abstract} } - class PriceClientImpl { - + PriceClientImpl() - + getPrice() : String - } - class ImageClientImpl { - + ImageClientImpl() - + getImagePath() : String - } - class App { - + App() - + main(args : String[]) {static} - } } ApiGateway --> "-imageClient" ImageClient ApiGateway --> "-priceClient" PriceClient diff --git a/async-method-invocation/etc/async-method-invocation.urm.puml b/async-method-invocation/etc/async-method-invocation.urm.puml index 9a90d307e..b96e843d3 100644 --- a/async-method-invocation/etc/async-method-invocation.urm.puml +++ b/async-method-invocation/etc/async-method-invocation.urm.puml @@ -1,13 +1,22 @@ @startuml package com.iluwatar.async.method.invocation { - interface AsyncCallback { - + onComplete(T, Optional) {abstract} + class App { + + App() + - callback(name : String) : AsyncCallback {static} + - lazyval(value : T, delayMillis : long) : Callable {static} + - log(msg : String) {static} + + main(args : String[]) {static} } interface AsyncResult { + await() {abstract} + getValue() : T {abstract} + isCompleted() : boolean {abstract} } + interface AsyncExecutor { + + endProcess(AsyncResult) : T {abstract} + + startProcess(Callable) : AsyncResult {abstract} + + startProcess(Callable, AsyncCallback) : AsyncResult {abstract} + } class ThreadAsyncExecutor { - idx : AtomicInteger + ThreadAsyncExecutor() @@ -15,12 +24,8 @@ package com.iluwatar.async.method.invocation { + startProcess(task : Callable) : AsyncResult + startProcess(task : Callable, callback : AsyncCallback) : AsyncResult } - class App { - + App() - - callback(name : String) : AsyncCallback {static} - - lazyval(value : T, delayMillis : long) : Callable {static} - - log(msg : String) {static} - + main(args : String[]) {static} + interface AsyncCallback { + + onComplete(T, Optional) {abstract} } -class CompletableResult { ~ COMPLETED : int {static} @@ -38,11 +43,6 @@ package com.iluwatar.async.method.invocation { ~ setException(exception : Exception) ~ setValue(value : T) } - interface AsyncExecutor { - + endProcess(AsyncResult) : T {abstract} - + startProcess(Callable) : AsyncResult {abstract} - + startProcess(Callable, AsyncCallback) : AsyncResult {abstract} - } } CompletableResult ..+ ThreadAsyncExecutor ThreadAsyncExecutor ..|> AsyncExecutor diff --git a/bridge/etc/bridge.urm.puml b/bridge/etc/bridge.urm.puml index d9d7a4145..84e250a06 100644 --- a/bridge/etc/bridge.urm.puml +++ b/bridge/etc/bridge.urm.puml @@ -8,26 +8,6 @@ package com.iluwatar.bridge { + unwield() + wield() } - abstract class MagicWeapon { - # imp : MagicWeaponImpl - + MagicWeapon(imp : MagicWeaponImpl) - + getImp() : MagicWeaponImpl - + swing() {abstract} - + unwield() {abstract} - + wield() {abstract} - } - abstract class SoulEatingMagicWeaponImpl { - + SoulEatingMagicWeaponImpl() - + eatSoulImp() {abstract} - } - class BlindingMagicWeapon { - + BlindingMagicWeapon(imp : BlindingMagicWeaponImpl) - + blind() - + getImp() : BlindingMagicWeaponImpl - + swing() - + unwield() - + wield() - } class Stormbringer { + Stormbringer() + eatSoulImp() @@ -35,9 +15,9 @@ package com.iluwatar.bridge { + unwieldImp() + wieldImp() } - abstract class BlindingMagicWeaponImpl { - + BlindingMagicWeaponImpl() - + blindImp() {abstract} + abstract class FlyingMagicWeaponImpl { + + FlyingMagicWeaponImpl() + + flyImp() {abstract} } class SoulEatingMagicWeapon { + SoulEatingMagicWeapon(imp : SoulEatingMagicWeaponImpl) @@ -53,6 +33,10 @@ package com.iluwatar.bridge { + unwieldImp() {abstract} + wieldImp() {abstract} } + abstract class SoulEatingMagicWeaponImpl { + + SoulEatingMagicWeaponImpl() + + eatSoulImp() {abstract} + } class Excalibur { + Excalibur() + blindImp() @@ -60,10 +44,6 @@ package com.iluwatar.bridge { + unwieldImp() + wieldImp() } - abstract class FlyingMagicWeaponImpl { - + FlyingMagicWeaponImpl() - + flyImp() {abstract} - } class Mjollnir { + Mjollnir() + flyImp() @@ -75,15 +55,35 @@ package com.iluwatar.bridge { + App() + main(args : String[]) {static} } + abstract class MagicWeapon { + # imp : MagicWeaponImpl + + MagicWeapon(imp : MagicWeaponImpl) + + getImp() : MagicWeaponImpl + + swing() {abstract} + + unwield() {abstract} + + wield() {abstract} + } + abstract class BlindingMagicWeaponImpl { + + BlindingMagicWeaponImpl() + + blindImp() {abstract} + } + class BlindingMagicWeapon { + + BlindingMagicWeapon(imp : BlindingMagicWeaponImpl) + + blind() + + getImp() : BlindingMagicWeaponImpl + + swing() + + unwield() + + wield() + } } MagicWeapon --> "-imp" MagicWeaponImpl FlyingMagicWeapon --|> MagicWeapon -SoulEatingMagicWeaponImpl --|> MagicWeaponImpl -BlindingMagicWeapon --|> MagicWeapon Stormbringer --|> SoulEatingMagicWeaponImpl -BlindingMagicWeaponImpl --|> MagicWeaponImpl -SoulEatingMagicWeapon --|> MagicWeapon -Excalibur --|> BlindingMagicWeaponImpl FlyingMagicWeaponImpl --|> MagicWeaponImpl +SoulEatingMagicWeapon --|> MagicWeapon +SoulEatingMagicWeaponImpl --|> MagicWeaponImpl +Excalibur --|> BlindingMagicWeaponImpl Mjollnir --|> FlyingMagicWeaponImpl +BlindingMagicWeaponImpl --|> MagicWeaponImpl +BlindingMagicWeapon --|> MagicWeapon @enduml \ No newline at end of file diff --git a/builder/etc/builder.urm.puml b/builder/etc/builder.urm.puml index 262476329..0c98f3b4b 100644 --- a/builder/etc/builder.urm.puml +++ b/builder/etc/builder.urm.puml @@ -1,5 +1,23 @@ @startuml package com.iluwatar.builder { + class Builder { + - armor : Armor + - hairColor : HairColor + - hairType : HairType + - name : String + - profession : Profession + - weapon : Weapon + + Builder(profession : Profession, name : String) + + build() : Hero + + withArmor(armor : Armor) : Builder + + withHairColor(hairColor : HairColor) : Builder + + withHairType(hairType : HairType) : Builder + + withWeapon(weapon : Weapon) : Builder + } + class App { + + App() + + main(args : String[]) {static} + } class Hero { - armor : Armor - hairColor : HairColor @@ -16,33 +34,25 @@ package com.iluwatar.builder { + getWeapon() : Weapon + toString() : String } - class App { - + App() - + main(args : String[]) {static} - } - class Builder { - - armor : Armor - - hairColor : HairColor - - hairType : HairType - - name : String - - profession : Profession - - weapon : Weapon - + Builder(profession : Profession, name : String) - + build() : Hero - + withArmor(armor : Armor) : Builder - + withHairColor(hairColor : HairColor) : Builder - + withHairType(hairType : HairType) : Builder - + withWeapon(weapon : Weapon) : Builder - } - enum Armor { - + CHAIN_MAIL {static} - + CLOTHES {static} - + LEATHER {static} - + PLATE_MAIL {static} - - title : String + enum Weapon { + + AXE {static} + + BOW {static} + + DAGGER {static} + + SWORD {static} + + WARHAMMER {static} + toString() : String - + valueOf(name : String) : Armor {static} - + values() : Armor[] {static} + + valueOf(name : String) : Weapon {static} + + values() : Weapon[] {static} + } + enum HairColor { + + BLACK {static} + + BLOND {static} + + BROWN {static} + + RED {static} + + WHITE {static} + + toString() : String + + valueOf(name : String) : HairColor {static} + + values() : HairColor[] {static} } enum Profession { + MAGE {static} @@ -53,15 +63,15 @@ package com.iluwatar.builder { + valueOf(name : String) : Profession {static} + values() : Profession[] {static} } - enum Weapon { - + AXE {static} - + BOW {static} - + DAGGER {static} - + SWORD {static} - + WARHAMMER {static} + enum Armor { + + CHAIN_MAIL {static} + + CLOTHES {static} + + LEATHER {static} + + PLATE_MAIL {static} + - title : String + toString() : String - + valueOf(name : String) : Weapon {static} - + values() : Weapon[] {static} + + valueOf(name : String) : Armor {static} + + values() : Armor[] {static} } enum HairType { + BALD {static} @@ -74,19 +84,9 @@ package com.iluwatar.builder { + valueOf(name : String) : HairType {static} + values() : HairType[] {static} } - enum HairColor { - + BLACK {static} - + BLOND {static} - + BROWN {static} - + RED {static} - + WHITE {static} - + toString() : String - + valueOf(name : String) : HairColor {static} - + values() : HairColor[] {static} - } } -Builder ..+ Hero Hero --> "-profession" Profession +Builder ..+ Hero Hero --> "-armor" Armor App --+ Hero Builder --> "-weapon" Weapon diff --git a/business-delegate/etc/business-delegate.urm.puml b/business-delegate/etc/business-delegate.urm.puml index a8f31700b..a58136c8c 100644 --- a/business-delegate/etc/business-delegate.urm.puml +++ b/business-delegate/etc/business-delegate.urm.puml @@ -1,5 +1,9 @@ @startuml package com.iluwatar.business.delegate { + class EjbService { + + EjbService() + + doProcessing() + } class BusinessLookup { - ejbService : EjbService - jmsService : JmsService @@ -8,15 +12,18 @@ package com.iluwatar.business.delegate { + setEjbService(ejbService : EjbService) + setJmsService(jmsService : JmsService) } + class App { + + App() + + main(args : String[]) {static} + } + interface BusinessService { + + doProcessing() {abstract} + } class Client { - businessDelegate : BusinessDelegate + Client(businessDelegate : BusinessDelegate) + doTask() } - class EjbService { - + EjbService() - + doProcessing() - } class BusinessDelegate { - businessService : BusinessService - lookupService : BusinessLookup @@ -26,17 +33,10 @@ package com.iluwatar.business.delegate { + setLookupService(businessLookup : BusinessLookup) + setServiceType(serviceType : ServiceType) } - interface BusinessService { - + doProcessing() {abstract} - } class JmsService { + JmsService() + doProcessing() } - class App { - + App() - + main(args : String[]) {static} - } enum ServiceType { + EJB {static} + JMS {static} diff --git a/caching/etc/caching.urm.puml b/caching/etc/caching.urm.puml index 273c9911c..b8f4fb49b 100644 --- a/caching/etc/caching.urm.puml +++ b/caching/etc/caching.urm.puml @@ -1,17 +1,18 @@ @startuml package com.iluwatar.caching { - class UserAccount { - - additionalInfo : String - - userId : String - - userName : String - + UserAccount(userId : String, userName : String, additionalInfo : String) - + getAdditionalInfo() : String - + getUserId() : String - + getUserName() : String - + setAdditionalInfo(additionalInfo : String) - + setUserId(userId : String) - + setUserName(userName : String) - + toString() : String + class App { + + App() + + main(args : String[]) {static} + + useReadAndWriteThroughStrategy() + + useReadThroughAndWriteAroundStrategy() + + useReadThroughAndWriteBehindStrategy() + } + ~class Node { + ~ next : Node + ~ previous : Node + ~ userAccount : UserAccount + ~ userId : String + + Node(this$0 : String, userId : UserAccount) } class CacheStore { ~ cache : LruCache {static} @@ -36,12 +37,18 @@ package com.iluwatar.caching { + printCacheContent() : String {static} + save(userAccount : UserAccount) {static} } - ~class Node { - ~ next : Node - ~ previous : Node - ~ userAccount : UserAccount - ~ userId : String - + Node(this$0 : LruCache, userId : String, userAccount : UserAccount) + class UserAccount { + - additionalInfo : String + - userId : String + - userName : String + + UserAccount(userId : String, userName : String, additionalInfo : String) + + getAdditionalInfo() : String + + getUserId() : String + + getUserName() : String + + setAdditionalInfo(additionalInfo : String) + + setUserId(userId : String) + + setUserName(userName : String) + + toString() : String } class LruCache { ~ cache : Map @@ -74,13 +81,6 @@ package com.iluwatar.caching { + upsertDb(userAccount : UserAccount) {static} + writeToDb(userAccount : UserAccount) {static} } - class App { - + App() - + main(args : String[]) {static} - + useReadAndWriteThroughStrategy() - + useReadThroughAndWriteAroundStrategy() - + useReadThroughAndWriteBehindStrategy() - } enum CachingPolicy { + AROUND {static} + BEHIND {static} diff --git a/callback/etc/callback.urm.puml b/callback/etc/callback.urm.puml index 8b27ee8a8..b9e1ca694 100644 --- a/callback/etc/callback.urm.puml +++ b/callback/etc/callback.urm.puml @@ -1,24 +1,24 @@ @startuml package com.iluwatar.callback { - class LambdasApp { - + LambdasApp() - + main(args : String[]) {static} - } - class SimpleTask { - + SimpleTask() - + execute() - } - class App { - + App() - + main(args : String[]) {static} + interface Callback { + + call() {abstract} } abstract class Task { + Task() + execute() {abstract} + executeWith(callback : Callback) } - interface Callback { - + call() {abstract} + class App { + + App() + + main(args : String[]) {static} + } + class SimpleTask { + + SimpleTask() + + execute() + } + class LambdasApp { + + LambdasApp() + + main(args : String[]) {static} } } SimpleTask --|> Task diff --git a/chain/etc/chain.urm.puml b/chain/etc/chain.urm.puml index c75cbc8d1..21365765d 100644 --- a/chain/etc/chain.urm.puml +++ b/chain/etc/chain.urm.puml @@ -1,13 +1,20 @@ @startuml package com.iluwatar.chain { + class OrcSoldier { + + OrcSoldier(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } class OrcCommander { + OrcCommander(handler : RequestHandler) + handleRequest(req : Request) + toString() : String } - class App { - + App() - + main(args : String[]) {static} + class OrcKing { + ~ chain : RequestHandler + + OrcKing() + - buildChain() + + makeRequest(req : Request) } class Request { - handled : boolean @@ -20,21 +27,9 @@ package com.iluwatar.chain { + markHandled() + toString() : String } - class OrcOfficer { - + OrcOfficer(handler : RequestHandler) - + handleRequest(req : Request) - + toString() : String - } - class OrcKing { - ~ chain : RequestHandler - + OrcKing() - - buildChain() - + makeRequest(req : Request) - } - class OrcSoldier { - + OrcSoldier(handler : RequestHandler) - + handleRequest(req : Request) - + toString() : String + class App { + + App() + + main(args : String[]) {static} } abstract class RequestHandler { - next : RequestHandler @@ -43,6 +38,11 @@ package com.iluwatar.chain { # printHandling(req : Request) + toString() : String {abstract} } + class OrcOfficer { + + OrcOfficer(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } enum RequestType { + COLLECT_TAX {static} + DEFEND_CASTLE {static} @@ -52,9 +52,9 @@ package com.iluwatar.chain { } } RequestHandler --> "-next" RequestHandler -OrcKing --> "-chain" RequestHandler Request --> "-requestType" RequestType +OrcKing --> "-chain" RequestHandler +OrcSoldier --|> RequestHandler OrcCommander --|> RequestHandler OrcOfficer --|> RequestHandler -OrcSoldier --|> RequestHandler @enduml \ No newline at end of file diff --git a/command/etc/command.urm.puml b/command/etc/command.urm.puml index 015fb30be..27bff7330 100644 --- a/command/etc/command.urm.puml +++ b/command/etc/command.urm.puml @@ -1,29 +1,5 @@ @startuml package com.iluwatar.command { - abstract class Target { - - size : Size - - visibility : Visibility - + Target() - + getSize() : Size - + getVisibility() : Visibility - + printStatus() - + setSize(size : Size) - + setVisibility(visibility : Visibility) - + toString() : String {abstract} - } - class Goblin { - + Goblin() - + toString() : String - } - class ShrinkSpell { - - oldSize : Size - - target : Target - + ShrinkSpell() - + execute(target : Target) - + redo() - + toString() : String - + undo() - } class InvisibilitySpell { - target : Target + InvisibilitySpell() @@ -32,15 +8,6 @@ package com.iluwatar.command { + toString() : String + undo() } - class Wizard { - - redoStack : Deque - - undoStack : Deque - + Wizard() - + castSpell(command : Command, target : Target) - + redoLastSpell() - + toString() : String - + undoLastSpell() - } class App { + App() + main(args : String[]) {static} @@ -52,6 +19,39 @@ package com.iluwatar.command { + toString() : String {abstract} + undo() {abstract} } + class Goblin { + + Goblin() + + toString() : String + } + abstract class Target { + - size : Size + - visibility : Visibility + + Target() + + getSize() : Size + + getVisibility() : Visibility + + printStatus() + + setSize(size : Size) + + setVisibility(visibility : Visibility) + + toString() : String {abstract} + } + class Wizard { + - redoStack : Deque + - undoStack : Deque + + Wizard() + + castSpell(command : Command, target : Target) + + redoLastSpell() + + toString() : String + + undoLastSpell() + } + class ShrinkSpell { + - oldSize : Size + - target : Target + + ShrinkSpell() + + execute(target : Target) + + redo() + + toString() : String + + undo() + } enum Size { + LARGE {static} + NORMAL {static} @@ -78,7 +78,7 @@ ShrinkSpell --> "-oldSize" Size InvisibilitySpell --> "-target" Target ShrinkSpell --> "-target" Target Target --> "-visibility" Visibility +InvisibilitySpell --|> Command Goblin --|> Target ShrinkSpell --|> Command -InvisibilitySpell --|> Command @enduml \ No newline at end of file diff --git a/composite/etc/composite.urm.puml b/composite/etc/composite.urm.puml index 6f6e93c98..82e9b65eb 100644 --- a/composite/etc/composite.urm.puml +++ b/composite/etc/composite.urm.puml @@ -1,5 +1,19 @@ @startuml package com.iluwatar.composite { + class Word { + + Word(letters : List) + # printThisAfter() + # printThisBefore() + } + class App { + + App() + + main(args : String[]) {static} + } + class Messenger { + + Messenger() + ~ messageFromElves() : LetterComposite + ~ messageFromOrcs() : LetterComposite + } class Letter { - c : char + Letter(c : char) @@ -11,20 +25,6 @@ package com.iluwatar.composite { # printThisAfter() # printThisBefore() } - class Word { - + Word(letters : List) - # printThisAfter() - # printThisBefore() - } - class Messenger { - + Messenger() - ~ messageFromElves() : LetterComposite - ~ messageFromOrcs() : LetterComposite - } - class App { - + App() - + main(args : String[]) {static} - } abstract class LetterComposite { - children : List + LetterComposite() @@ -36,7 +36,7 @@ package com.iluwatar.composite { } } LetterComposite --> "-children" LetterComposite +Word --|> LetterComposite Letter --|> LetterComposite Sentence --|> LetterComposite -Word --|> LetterComposite @enduml \ No newline at end of file diff --git a/dao/etc/dao.urm.puml b/dao/etc/dao.urm.puml index f751b967c..90a9c9725 100644 --- a/dao/etc/dao.urm.puml +++ b/dao/etc/dao.urm.puml @@ -1,5 +1,49 @@ @startuml package com.iluwatar.dao { + class InMemoryCustomerDao { + - idToCustomer : Map + + InMemoryCustomerDao() + + add(customer : Customer) : boolean + + delete(customer : Customer) : boolean + + getAll() : Stream + + getById(id : int) : Optional + + update(customer : Customer) : boolean + } + interface CustomerSchemaSql { + + CREATE_SCHEMA_SQL : String {static} + + DELETE_SCHEMA_SQL : String {static} + } + interface CustomerDao { + + add(Customer) : boolean {abstract} + + delete(Customer) : boolean {abstract} + + getAll() : Stream {abstract} + + getById(int) : Optional {abstract} + + update(Customer) : boolean {abstract} + } + class App { + - DB_URL : String {static} + - log : 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 DbCustomerDao { + - 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) + + update(customer : Customer) : boolean + } class Customer { - firstName : String - id : int @@ -15,51 +59,7 @@ package com.iluwatar.dao { + 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 DbCustomerDao { - - 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) - + 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 - } - interface CustomerSchemaSql { - + CREATE_SCHEMA_SQL : String {static} - + DELETE_SCHEMA_SQL : String {static} - } - class App { - - DB_URL : String {static} - - log : 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} - } } -DbCustomerDao ..|> CustomerDao InMemoryCustomerDao ..|> CustomerDao +DbCustomerDao ..|> CustomerDao @enduml \ No newline at end of file diff --git a/decorator/etc/decorator.urm.puml b/decorator/etc/decorator.urm.puml index 6c44e6cc9..4862ddfeb 100644 --- a/decorator/etc/decorator.urm.puml +++ b/decorator/etc/decorator.urm.puml @@ -1,5 +1,10 @@ @startuml package com.iluwatar.decorator { + interface Hostile { + + attack() {abstract} + + fleeBattle() {abstract} + + getAttackPower() : int {abstract} + } class App { + App() + main(args : String[]) {static} @@ -10,11 +15,6 @@ package com.iluwatar.decorator { + fleeBattle() + getAttackPower() : int } - interface Hostile { - + attack() {abstract} - + fleeBattle() {abstract} - + getAttackPower() : int {abstract} - } class SmartHostile { - decorated : Hostile + SmartHostile(decorated : Hostile) diff --git a/delegation/etc/delegation.urm.puml b/delegation/etc/delegation.urm.puml index c143a6ba0..378587019 100644 --- a/delegation/etc/delegation.urm.puml +++ b/delegation/etc/delegation.urm.puml @@ -1,19 +1,24 @@ @startuml package com.iluwatar.delegation.simple.printers { - class EpsonPrinter { - + EpsonPrinter() - + print(message : String) - } class HpPrinter { + HpPrinter() + print(message : String) } + class EpsonPrinter { + + EpsonPrinter() + + print(message : String) + } class CanonPrinter { + CanonPrinter() + print(message : String) } } package com.iluwatar.delegation.simple { + class App { + + MESSAGE_TO_PRINT : String {static} + + App() + + main(args : String[]) {static} + } class PrinterController { - printer : Printer + PrinterController(printer : Printer) @@ -22,15 +27,10 @@ package com.iluwatar.delegation.simple { interface Printer { + print(String) {abstract} } - class App { - + MESSAGE_TO_PRINT : String {static} - + App() - + main(args : String[]) {static} - } } PrinterController --> "-printer" Printer +HpPrinter ..|> Printer PrinterController ..|> Printer EpsonPrinter ..|> Printer -HpPrinter ..|> Printer CanonPrinter ..|> Printer @enduml \ No newline at end of file diff --git a/dependency-injection/etc/dependency-injection.urm.puml b/dependency-injection/etc/dependency-injection.urm.puml index c22c658ad..bf4d10599 100644 --- a/dependency-injection/etc/dependency-injection.urm.puml +++ b/dependency-injection/etc/dependency-injection.urm.puml @@ -1,48 +1,48 @@ @startuml package com.iluwatar.dependency.injection { - interface Wizard { - + smoke() {abstract} - } - class GuiceWizard { - - tobacco : Tobacco - + GuiceWizard(tobacco : Tobacco) - + smoke() - } - class OldTobyTobacco { - + OldTobyTobacco() - } - abstract class Tobacco { - + Tobacco() - + smoke(wizard : Wizard) - } - class App { - + App() - + main(args : String[]) {static} - } - class RivendellTobacco { - + RivendellTobacco() - } class AdvancedWizard { - tobacco : Tobacco + AdvancedWizard(tobacco : Tobacco) + smoke() } - class SecondBreakfastTobacco { - + SecondBreakfastTobacco() + interface Wizard { + + smoke() {abstract} + } + class RivendellTobacco { + + RivendellTobacco() } class SimpleWizard { - tobacco : OldTobyTobacco + SimpleWizard() + smoke() } + class OldTobyTobacco { + + OldTobyTobacco() + } + class SecondBreakfastTobacco { + + SecondBreakfastTobacco() + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class Tobacco { + + Tobacco() + + smoke(wizard : Wizard) + } + class GuiceWizard { + - tobacco : Tobacco + + GuiceWizard(tobacco : Tobacco) + + smoke() + } } SimpleWizard --> "-tobacco" OldTobyTobacco AdvancedWizard --> "-tobacco" Tobacco GuiceWizard --> "-tobacco" Tobacco -GuiceWizard ..|> Wizard -OldTobyTobacco --|> Tobacco -RivendellTobacco --|> Tobacco AdvancedWizard ..|> Wizard -SecondBreakfastTobacco --|> Tobacco +RivendellTobacco --|> Tobacco SimpleWizard ..|> Wizard +OldTobyTobacco --|> Tobacco +SecondBreakfastTobacco --|> Tobacco +GuiceWizard ..|> Wizard @enduml \ No newline at end of file diff --git a/double-dispatch/etc/double-dispatch.urm.puml b/double-dispatch/etc/double-dispatch.urm.puml index 725f009c0..78d361326 100644 --- a/double-dispatch/etc/double-dispatch.urm.puml +++ b/double-dispatch/etc/double-dispatch.urm.puml @@ -1,17 +1,5 @@ @startuml package com.iluwatar.doubledispatch { - class App { - + App() - + main(args : String[]) {static} - } - class FlamingAsteroid { - + FlamingAsteroid(left : int, top : int, right : int, bottom : int) - + collision(gameObject : GameObject) - } - class SpaceStationIss { - + SpaceStationIss(left : int, top : int, right : int, bottom : int) - + collision(gameObject : GameObject) - } abstract class GameObject { - damaged : boolean - onFire : boolean @@ -27,6 +15,14 @@ package com.iluwatar.doubledispatch { + setOnFire(onFire : boolean) + toString() : String } + class SpaceStationIss { + + SpaceStationIss(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + } + class FlamingAsteroid { + + FlamingAsteroid(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + } class SpaceStationMir { + SpaceStationMir(left : int, top : int, right : int, bottom : int) + collision(gameObject : GameObject) @@ -56,10 +52,14 @@ package com.iluwatar.doubledispatch { ~ intersectsWith(r : Rectangle) : boolean + toString() : String } + class App { + + App() + + main(args : String[]) {static} + } } -FlamingAsteroid --|> Meteoroid -SpaceStationIss --|> SpaceStationMir GameObject --|> Rectangle +SpaceStationIss --|> SpaceStationMir +FlamingAsteroid --|> Meteoroid SpaceStationMir --|> GameObject Meteoroid --|> GameObject @enduml \ No newline at end of file diff --git a/event-aggregator/etc/event-aggregator.urm.puml b/event-aggregator/etc/event-aggregator.urm.puml index 18b7621c9..3ccfea536 100644 --- a/event-aggregator/etc/event-aggregator.urm.puml +++ b/event-aggregator/etc/event-aggregator.urm.puml @@ -1,34 +1,10 @@ @startuml package com.iluwatar.event.aggregator { - class KingsHand { - + KingsHand() - + KingsHand(obs : EventObserver) - + onEvent(e : Event) - + timePasses(day : Weekday) - } - class KingJoffrey { - + KingJoffrey() - + onEvent(e : Event) - } - class Scout { - + Scout() - + Scout(obs : EventObserver) - + timePasses(day : Weekday) - } class LordVarys { + LordVarys() + LordVarys(obs : EventObserver) + timePasses(day : Weekday) } - class App { - + App() - + main(args : String[]) {static} - } - class LordBaelish { - + LordBaelish() - + LordBaelish(obs : EventObserver) - + timePasses(day : Weekday) - } abstract class EventEmitter { - observers : List + EventEmitter() @@ -37,9 +13,33 @@ package com.iluwatar.event.aggregator { + registerObserver(obs : EventObserver) + timePasses(Weekday) {abstract} } + class KingJoffrey { + + KingJoffrey() + + onEvent(e : Event) + } + class LordBaelish { + + LordBaelish() + + LordBaelish(obs : EventObserver) + + timePasses(day : Weekday) + } interface EventObserver { + onEvent(Event) {abstract} } + class KingsHand { + + KingsHand() + + KingsHand(obs : EventObserver) + + onEvent(e : Event) + + timePasses(day : Weekday) + } + class Scout { + + Scout() + + Scout(obs : EventObserver) + + timePasses(day : Weekday) + } + class App { + + App() + + main(args : String[]) {static} + } enum Weekday { + FRIDAY {static} + MONDAY {static} @@ -64,10 +64,10 @@ package com.iluwatar.event.aggregator { } } EventEmitter --> "-observers" EventObserver +LordVarys --|> EventEmitter +KingJoffrey ..|> EventObserver +LordBaelish --|> EventEmitter KingsHand ..|> EventObserver KingsHand --|> EventEmitter -KingJoffrey ..|> EventObserver Scout --|> EventEmitter -LordVarys --|> EventEmitter -LordBaelish --|> EventEmitter @enduml \ No newline at end of file diff --git a/event-driven-architecture/etc/event-driven-architecture.urm.puml b/event-driven-architecture/etc/event-driven-architecture.urm.puml index 55039190f..8314913a6 100644 --- a/event-driven-architecture/etc/event-driven-architecture.urm.puml +++ b/event-driven-architecture/etc/event-driven-architecture.urm.puml @@ -1,31 +1,34 @@ @startuml package com.iluwatar.eda.handler { - class UserUpdatedEventHandler { - + UserUpdatedEventHandler() - + onEvent(event : UserUpdatedEvent) - } class UserCreatedEventHandler { + UserCreatedEventHandler() + onEvent(event : UserCreatedEvent) } + class UserUpdatedEventHandler { + + UserUpdatedEventHandler() + + onEvent(event : UserUpdatedEvent) + } } package com.iluwatar.eda.event { abstract class AbstractEvent { + AbstractEvent() + getType() : Class } - class UserUpdatedEvent { - - user : User - + UserUpdatedEvent(user : User) - + getUser() : User - } class UserCreatedEvent { - user : User + UserCreatedEvent(user : User) + getUser() : User } + class UserUpdatedEvent { + - user : User + + UserUpdatedEvent(user : User) + + getUser() : User + } } package com.iluwatar.eda.framework { + interface Handler { + + onEvent(E extends Event) {abstract} + } class EventDispatcher { - handlers : Map, Handler> + EventDispatcher() @@ -35,9 +38,6 @@ package com.iluwatar.eda.framework { interface Event { + getType() : Class {abstract} } - interface Handler { - + onEvent(E extends Event) {abstract} - } } package com.iluwatar.eda.model { class User { @@ -52,11 +52,11 @@ package com.iluwatar.eda { + main(args : String[]) {static} } } -UserCreatedEvent --> "-user" User UserUpdatedEvent --> "-user" User +UserCreatedEvent --> "-user" User AbstractEvent ..|> Event -UserUpdatedEventHandler ..|> Handler +UserCreatedEvent --|> AbstractEvent UserCreatedEventHandler ..|> Handler UserUpdatedEvent --|> AbstractEvent -UserCreatedEvent --|> AbstractEvent +UserUpdatedEventHandler ..|> Handler @enduml \ No newline at end of file diff --git a/execute-around/etc/execute-around.urm.puml b/execute-around/etc/execute-around.urm.puml index 66d23ce7a..4fdc4bffb 100644 --- a/execute-around/etc/execute-around.urm.puml +++ b/execute-around/etc/execute-around.urm.puml @@ -1,8 +1,5 @@ @startuml package com.iluwatar.execute.around { - interface FileWriterAction { - + writeFile(FileWriter) {abstract} - } class SimpleFileWriter { + SimpleFileWriter(filename : String, action : FileWriterAction) } @@ -10,5 +7,8 @@ package com.iluwatar.execute.around { + App() + main(args : String[]) {static} } + interface FileWriterAction { + + writeFile(FileWriter) {abstract} + } } @enduml \ No newline at end of file diff --git a/facade/etc/facade.urm.puml b/facade/etc/facade.urm.puml index f72bc2b62..8c53cb728 100644 --- a/facade/etc/facade.urm.puml +++ b/facade/etc/facade.urm.puml @@ -1,7 +1,7 @@ @startuml package com.iluwatar.facade { - class DwarvenTunnelDigger { - + DwarvenTunnelDigger() + class DwarvenGoldDigger { + + DwarvenGoldDigger() + name() : String + work() } @@ -13,15 +13,11 @@ package com.iluwatar.facade { - makeActions(workers : Collection, actions : Action[]) {static} + startNewDay() } - class DwarvenGoldDigger { - + DwarvenGoldDigger() + class DwarvenTunnelDigger { + + DwarvenTunnelDigger() + name() : String + work() } - class App { - + App() - + main(args : String[]) {static} - } abstract class DwarvenMineWorker { + DwarvenMineWorker() - action(action : Action) @@ -33,6 +29,10 @@ package com.iluwatar.facade { + wakeUp() + work() {abstract} } + class App { + + App() + + main(args : String[]) {static} + } class DwarvenCartOperator { + DwarvenCartOperator() + name() : String @@ -51,7 +51,7 @@ package com.iluwatar.facade { DwarvenGoldmineFacade --+ DwarvenMineWorker DwarvenGoldmineFacade --> "-workers" DwarvenMineWorker Action ..+ DwarvenMineWorker -DwarvenTunnelDigger --|> DwarvenMineWorker DwarvenGoldDigger --|> DwarvenMineWorker +DwarvenTunnelDigger --|> DwarvenMineWorker DwarvenCartOperator --|> DwarvenMineWorker @enduml \ No newline at end of file diff --git a/factory-kit/etc/factory-kit.urm.puml b/factory-kit/etc/factory-kit.urm.puml index faf5727eb..fdee9a01c 100644 --- a/factory-kit/etc/factory-kit.urm.puml +++ b/factory-kit/etc/factory-kit.urm.puml @@ -1,33 +1,33 @@ @startuml package com.iluwatar.factorykit { - interface Builder { - + add(WeaponType, Supplier) {abstract} - } class Spear { + Spear() + toString() : String } - class Bow { - + Bow() + class App { + + App() + + main(args : String[]) {static} + } + interface Weapon { + } + interface WeaponFactory { + + create(WeaponType) : Weapon {abstract} + + factory(consumer : Consumer) : WeaponFactory {static} + } + class Axe { + + Axe() + toString() : String } class Sword { + Sword() + toString() : String } - interface Weapon { - } - class App { - + App() - + main(args : String[]) {static} - } - class Axe { - + Axe() + class Bow { + + Bow() + toString() : String } - interface WeaponFactory { - + create(WeaponType) : Weapon {abstract} - + factory(consumer : Consumer) : WeaponFactory {static} + interface Builder { + + add(WeaponType, Supplier) {abstract} } enum WeaponType { + AXE {static} @@ -39,7 +39,7 @@ package com.iluwatar.factorykit { } } Spear ..|> Weapon -Bow ..|> Weapon -Sword ..|> Weapon Axe ..|> Weapon +Sword ..|> Weapon +Bow ..|> Weapon @enduml \ No newline at end of file diff --git a/factory-method/etc/factory-method.urm.puml b/factory-method/etc/factory-method.urm.puml index ebc9d2ff7..d61984a85 100644 --- a/factory-method/etc/factory-method.urm.puml +++ b/factory-method/etc/factory-method.urm.puml @@ -17,9 +17,6 @@ package com.iluwatar.factory.method { interface Blacksmith { + manufactureWeapon(WeaponType) : Weapon {abstract} } - interface Weapon { - + getWeaponType() : WeaponType {abstract} - } class ElfWeapon { - weaponType : WeaponType + ElfWeapon(weaponType : WeaponType) @@ -32,6 +29,9 @@ package com.iluwatar.factory.method { + main(args : String[]) {static} - manufactureWeapons() } + interface Weapon { + + getWeaponType() : WeaponType {abstract} + } enum WeaponType { + AXE {static} + SHORT_SWORD {static} diff --git a/feature-toggle/etc/feature-toggle.urm.puml b/feature-toggle/etc/feature-toggle.urm.puml index 762d49cb3..6c935f3e6 100644 --- a/feature-toggle/etc/feature-toggle.urm.puml +++ b/feature-toggle/etc/feature-toggle.urm.puml @@ -20,17 +20,17 @@ package com.iluwatar.featuretoggle.user { + isPaid(user : User) : boolean {static} } } -package com.iluwatar.featuretoggle.pattern.propertiesversion { - class PropertiesFeatureToggleVersion { - - isEnhanced : boolean - + PropertiesFeatureToggleVersion(properties : Properties) +package com.iluwatar.featuretoggle.pattern.tieredversion { + class TieredFeatureToggleVersion { + + TieredFeatureToggleVersion() + getWelcomeMessage(user : User) : String + isEnhanced() : boolean } } -package com.iluwatar.featuretoggle.pattern.tieredversion { - class TieredFeatureToggleVersion { - + TieredFeatureToggleVersion() +package com.iluwatar.featuretoggle.pattern.propertiesversion { + class PropertiesFeatureToggleVersion { + - isEnhanced : boolean + + PropertiesFeatureToggleVersion(properties : Properties) + getWelcomeMessage(user : User) : String + isEnhanced() : boolean } @@ -42,6 +42,6 @@ package com.iluwatar.featuretoggle { } } UserGroup --> "-freeGroup" User -TieredFeatureToggleVersion ..|> Service PropertiesFeatureToggleVersion ..|> Service +TieredFeatureToggleVersion ..|> Service @enduml \ No newline at end of file diff --git a/fluentinterface/etc/fluentinterface.urm.puml b/fluentinterface/etc/fluentinterface.urm.puml index 436fcb2e8..0283e20b5 100644 --- a/fluentinterface/etc/fluentinterface.urm.puml +++ b/fluentinterface/etc/fluentinterface.urm.puml @@ -31,6 +31,14 @@ package com.iluwatar.fluentinterface.app { } } 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() @@ -45,14 +53,6 @@ package com.iluwatar.fluentinterface.fluentiterable.lazy { + last(count : int) : FluentIterable + map(function : Function) : FluentIterable } - abstract class DecoratingIterator { - # fromIterator : Iterator - - next : E - + DecoratingIterator(fromIterator : Iterator) - + computeNext() : E {abstract} - + hasNext() : boolean - + next() : E - } } package com.iluwatar.fluentinterface.fluentiterable { interface FluentIterable { diff --git a/flux/etc/flux.urm.puml b/flux/etc/flux.urm.puml index e4bece2fc..a4e0b0622 100644 --- a/flux/etc/flux.urm.puml +++ b/flux/etc/flux.urm.puml @@ -1,10 +1,8 @@ @startuml package com.iluwatar.flux.view { - class ContentView { - - content : Content - + ContentView() - + render() - + storeChanged(store : Store) + interface View { + + render() {abstract} + + storeChanged(Store) {abstract} } class MenuView { - selected : MenuItem @@ -13,27 +11,35 @@ package com.iluwatar.flux.view { + render() + storeChanged(store : Store) } - interface View { - + render() {abstract} - + storeChanged(Store) {abstract} + class ContentView { + - content : Content + + ContentView() + + render() + + storeChanged(store : Store) } } package com.iluwatar.flux.action { - class ContentAction { - - content : Content - + ContentAction(content : Content) - + getContent() : Content - } class MenuAction { - menuItem : MenuItem + MenuAction(menuItem : MenuItem) + getMenuItem() : MenuItem } + class ContentAction { + - content : Content + + ContentAction(content : Content) + + getContent() : Content + } abstract class Action { - type : ActionType + Action(type : ActionType) + getType() : ActionType } + enum ActionType { + + CONTENT_CHANGED {static} + + MENU_ITEM_SELECTED {static} + + valueOf(name : String) : ActionType {static} + + values() : ActionType[] {static} + } enum MenuItem { + COMPANY {static} + HOME {static} @@ -51,12 +57,6 @@ package com.iluwatar.flux.action { + valueOf(name : String) : Content {static} + values() : Content[] {static} } - enum ActionType { - + CONTENT_CHANGED {static} - + MENU_ITEM_SELECTED {static} - + valueOf(name : String) : ActionType {static} - + values() : ActionType[] {static} - } } package com.iluwatar.flux.app { class App { @@ -64,27 +64,6 @@ package com.iluwatar.flux.app { + main(args : String[]) {static} } } -package com.iluwatar.flux.store { - abstract class Store { - - views : List - + Store() - # notifyChange() - + onAction(Action) {abstract} - + registerView(view : View) - } - class ContentStore { - - content : Content - + ContentStore() - + getContent() : Content - + onAction(action : Action) - } - class MenuStore { - - selected : MenuItem - + MenuStore() - + getSelected() : MenuItem - + onAction(action : Action) - } -} package com.iluwatar.flux.dispatcher { class Dispatcher { - instance : Dispatcher {static} @@ -96,6 +75,27 @@ package com.iluwatar.flux.dispatcher { + registerStore(store : Store) } } +package com.iluwatar.flux.store { + class ContentStore { + - content : Content + + ContentStore() + + getContent() : Content + + onAction(action : Action) + } + class MenuStore { + - selected : MenuItem + + MenuStore() + + getSelected() : MenuItem + + onAction(action : Action) + } + abstract class Store { + - views : List + + Store() + # notifyChange() + + onAction(Action) {abstract} + + registerView(view : View) + } +} MenuAction --> "-menuItem" MenuItem Action --> "-type" ActionType MenuStore --> "-selected" MenuItem @@ -104,12 +104,12 @@ ContentView --> "-content" Content Dispatcher --> "-stores" Store MenuView --> "-selected" MenuItem Store --> "-views" View -ContentStore --> "-content" Content ContentAction --> "-content" Content -ContentAction --|> Action +ContentStore --> "-content" Content ContentStore --|> Store -ContentView ..|> View MenuAction --|> Action -MenuView ..|> View MenuStore --|> Store +ContentAction --|> Action +MenuView ..|> View +ContentView ..|> View @enduml \ No newline at end of file diff --git a/flyweight/etc/flyweight.urm.puml b/flyweight/etc/flyweight.urm.puml index 98a2b4721..3f2203712 100644 --- a/flyweight/etc/flyweight.urm.puml +++ b/flyweight/etc/flyweight.urm.puml @@ -1,28 +1,17 @@ @startuml package com.iluwatar.flyweight { - class PoisonPotion { - + PoisonPotion() - + drink() - } - class StrengthPotion { - + StrengthPotion() - + drink() - } - class HealingPotion { - + HealingPotion() - + drink() - } class PotionFactory { - potions : Map + PotionFactory() ~ createPotion(type : PotionType) : Potion } - interface Potion { - + drink() {abstract} + class HealingPotion { + + HealingPotion() + + drink() } - class App { - + App() - + main(args : String[]) {static} + class InvisibilityPotion { + + InvisibilityPotion() + + drink() } class AlchemistShop { - bottomShelf : List @@ -33,12 +22,23 @@ package com.iluwatar.flyweight { + getBottomShelf() : List + getTopShelf() : List } - class HolyWaterPotion { - + HolyWaterPotion() + class App { + + App() + + main(args : String[]) {static} + } + interface Potion { + + drink() {abstract} + } + class PoisonPotion { + + PoisonPotion() + drink() } - class InvisibilityPotion { - + InvisibilityPotion() + class StrengthPotion { + + StrengthPotion() + + drink() + } + class HolyWaterPotion { + + HolyWaterPotion() + drink() } enum PotionType { @@ -52,9 +52,9 @@ package com.iluwatar.flyweight { } } AlchemistShop --> "-topShelf" Potion +HealingPotion ..|> Potion +InvisibilityPotion ..|> Potion PoisonPotion ..|> Potion StrengthPotion ..|> Potion -HealingPotion ..|> Potion HolyWaterPotion ..|> Potion -InvisibilityPotion ..|> Potion @enduml \ No newline at end of file diff --git a/front-controller/etc/front-controller.urm.puml b/front-controller/etc/front-controller.urm.puml index 17ccebae1..8fb9be184 100644 --- a/front-controller/etc/front-controller.urm.puml +++ b/front-controller/etc/front-controller.urm.puml @@ -1,5 +1,20 @@ @startuml package com.iluwatar.front.controller { + class ArcherView { + + ArcherView() + + display() + } + interface View { + + display() {abstract} + } + class CatapultView { + + CatapultView() + + display() + } + class ArcherCommand { + + ArcherCommand() + + process() + } class App { + App() + main(args : String[]) {static} @@ -10,41 +25,26 @@ package com.iluwatar.front.controller { - getCommandClass(request : String) : Class {static} + handleRequest(request : String) } - class ArcherView { - + ArcherView() - + display() - } - interface View { - + display() {abstract} - } - interface Command { - + process() {abstract} + class UnknownCommand { + + UnknownCommand() + + process() } class ErrorView { + ErrorView() + display() } - class ArcherCommand { - + ArcherCommand() - + process() - } - class CatapultView { - + CatapultView() - + display() - } class CatapultCommand { + CatapultCommand() + process() } - class UnknownCommand { - + UnknownCommand() - + process() + interface Command { + + process() {abstract} } } ArcherView ..|> View -ErrorView ..|> View -ArcherCommand ..|> Command CatapultView ..|> View -CatapultCommand ..|> Command +ArcherCommand ..|> Command UnknownCommand ..|> Command +ErrorView ..|> View +CatapultCommand ..|> Command @enduml \ No newline at end of file diff --git a/half-sync-half-async/etc/half-sync-half-async.urm.puml b/half-sync-half-async/etc/half-sync-half-async.urm.puml index e733dd586..88f49eb4d 100644 --- a/half-sync-half-async/etc/half-sync-half-async.urm.puml +++ b/half-sync-half-async/etc/half-sync-half-async.urm.puml @@ -1,5 +1,18 @@ @startuml package com.iluwatar.halfsynchalfasync { + class AsynchronousService { + - service : ExecutorService + + AsynchronousService(workQueue : BlockingQueue) + + execute(task : AsyncTask) + } + ~class ArithmeticSumTask { + - n : long + + ArithmeticSumTask(n : long) + + call() : Long + + onError(throwable : Throwable) + + onPostCall(result : Long) + + onPreCall() + } class App { + App() - ap(i : long) : long {static} @@ -11,19 +24,6 @@ package com.iluwatar.halfsynchalfasync { + onPostCall(O) {abstract} + onPreCall() {abstract} } - ~class ArithmeticSumTask { - - n : long - + ArithmeticSumTask(n : long) - + call() : Long - + onError(throwable : Throwable) - + onPostCall(result : Long) - + onPreCall() - } - class AsynchronousService { - - service : ExecutorService - + AsynchronousService(workQueue : BlockingQueue) - + execute(task : AsyncTask) - } } ArithmeticSumTask ..+ App ArithmeticSumTask ..|> AsyncTask diff --git a/hexagonal/etc/hexagonal.urm.puml b/hexagonal/etc/hexagonal.urm.puml index c4b0d0a73..a2f5d0469 100644 --- a/hexagonal/etc/hexagonal.urm.puml +++ b/hexagonal/etc/hexagonal.urm.puml @@ -1,31 +1,47 @@ @startuml -package com.iluwatar.hexagonal.service { - class LotteryServiceImpl { - - bank : WireTransfers - - notifications : LotteryNotifications - - repository : LotteryTicketRepository - + LotteryServiceImpl() - + checkTicketForPrize(id : LotteryTicketId, winningNumbers : LotteryNumbers) : LotteryTicketCheckResult - + submitTicket(ticket : LotteryTicket) : Optional +package com.iluwatar.hexagonal.sampledata { + class SampleData { + - PLAYERS : List {static} + + SampleData() + - getRandomPlayerDetails() : PlayerDetails {static} + + submitTickets(lotteryService : LotteryService, numTickets : int) {static} } - interface LotteryService { - + checkTicketForPrize(LotteryTicketId, LotteryNumbers) : LotteryTicketCheckResult {abstract} - + submitTicket(LotteryTicket) : Optional {abstract} +} +package com.iluwatar.hexagonal.service { + class ConsoleLottery { + + ConsoleLottery() + + main(args : String[]) {static} + - printMainMenu() {static} + - readString(scanner : Scanner) : String {static} + } +} +package com.iluwatar.hexagonal.mongo { + class MongoConnectionPropertiesLoader { + - DEFAULT_HOST : String {static} + - DEFAULT_PORT : int {static} + + MongoConnectionPropertiesLoader() + + load() {static} } } package com.iluwatar.hexagonal.domain { class LotteryTicketId { - - id : UUID + - id : int + - numAllocated : int {static} + LotteryTicketId() - + getId() : UUID + + LotteryTicketId(id : int) + + equals(o : Object) : boolean + + getId() : int + + hashCode() : int + + toString() : String } - class LotteryConstants { - + PLAYER_MAX_SALDO : int {static} - + PRIZE_AMOUNT : int {static} - + SERVICE_BANK_ACCOUNT : String {static} - + SERVICE_BANK_ACCOUNT_SALDO : int {static} - + TICKET_PRIZE : int {static} - + LotteryConstants() + class LotteryAdministration { + - notifications : LotteryEventLog + - repository : LotteryTicketRepository + - wireTransfers : WireTransfers + + LotteryAdministration(repository : LotteryTicketRepository, notifications : LotteryEventLog, wireTransfers : WireTransfers) + + getAllSubmittedTickets() : Map + + performLottery() : LotteryNumbers + + resetLottery() } class LotteryNumbers { + MAX_NUMBER : int {static} @@ -39,19 +55,34 @@ package com.iluwatar.hexagonal.domain { + equals(obj : Object) : boolean - generateRandomNumbers() + getNumbers() : Set + + getNumbersAsString() : String + hashCode() : int + + toString() : String + } + 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 RandomNumberGenerator { + - randomIterator : OfInt + + RandomNumberGenerator(min : int, max : int) + + nextInt() : int } class PlayerDetails { - bankAccountNumber : String - emailAddress : String - phoneNumber : String - - PlayerDetails(email : String, bankAccount : String, phone : String) - + create(email : String, bankAccount : String, phone : String) : PlayerDetails {static} + + PlayerDetails(email : String, bankAccount : String, phone : String) + equals(obj : Object) : boolean + getBankAccount() : String + getEmail() : String + getPhoneNumber() : String + hashCode() : int + + toString() : String } class LotteryTicketCheckResult { - checkResult : CheckResult @@ -63,20 +94,30 @@ package com.iluwatar.hexagonal.domain { + getResult() : CheckResult + hashCode() : int } + class LotteryConstants { + + PLAYER_MAX_SALDO : int {static} + + PRIZE_AMOUNT : int {static} + + SERVICE_BANK_ACCOUNT : String {static} + + SERVICE_BANK_ACCOUNT_SALDO : int {static} + + TICKET_PRIZE : int {static} + - LotteryConstants() + } class LotteryTicket { + - id : LotteryTicketId - lotteryNumbers : LotteryNumbers - playerDetails : PlayerDetails - - LotteryTicket(details : PlayerDetails, numbers : LotteryNumbers) - + create(details : PlayerDetails, numbers : LotteryNumbers) : LotteryTicket {static} + + LotteryTicket(id : LotteryTicketId, details : PlayerDetails, numbers : LotteryNumbers) + equals(obj : Object) : boolean + + getId() : LotteryTicketId + getNumbers() : LotteryNumbers + getPlayerDetails() : PlayerDetails + hashCode() : int + + setId(id : LotteryTicketId) + + toString() : String } - -class RandomNumberGenerator { - - randomIterator : OfInt - + RandomNumberGenerator(min : int, max : int) - + nextInt() : int + class LotteryUtils { + - LotteryUtils() + + checkTicketForPrize(repository : LotteryTicketRepository, id : LotteryTicketId, winningNumbers : LotteryNumbers) : LotteryTicketCheckResult {static} } enum CheckResult { + NO_PRIZE {static} @@ -87,23 +128,64 @@ package com.iluwatar.hexagonal.domain { } } package com.iluwatar.hexagonal.banking { - class WireTransfersImpl { - - accounts : Map {static} - + WireTransfersImpl() - + getFunds(bankAccount : String) : int - + setFunds(bankAccount : String, amount : int) - + transferFunds(amount : int, sourceBackAccount : String, destinationBankAccount : String) : boolean - } interface WireTransfers { + getFunds(String) : int {abstract} + setFunds(String, int) {abstract} + transferFunds(int, String, String) : boolean {abstract} } + 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 + + getFunds(bankAccount : String) : int + + getMongoClient() : MongoClient + + getMongoDatabase() : MongoDatabase + + setFunds(bankAccount : String, amount : int) + + transferFunds(amount : int, sourceBackAccount : String, destinationBankAccount : String) : boolean + } + class InMemoryBank { + - accounts : Map {static} + + InMemoryBank() + + getFunds(bankAccount : String) : int + + setFunds(bankAccount : String, amount : int) + + transferFunds(amount : int, sourceBackAccount : String, destinationBankAccount : String) : boolean + } } package com.iluwatar.hexagonal.database { - class LotteryTicketInMemoryRepository { + class MongoTicketRepository { + - DEFAULT_COUNTERS_COLLECTION : String {static} + - DEFAULT_DB : String {static} + - DEFAULT_TICKETS_COLLECTION : 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 + + getMongoClient() : MongoClient + + getMongoDatabase() : MongoDatabase + + getNextId() : int + + getTicketsCollection() : MongoCollection + - initCounters() + + save(ticket : LotteryTicket) : Optional + } + class InMemoryTicketRepository { - tickets : Map {static} - + LotteryTicketInMemoryRepository() + + InMemoryTicketRepository() + deleteAll() + findAll() : Map + findById(id : LotteryTicketId) : Optional @@ -116,68 +198,79 @@ package com.iluwatar.hexagonal.database { + save(LotteryTicket) : Optional {abstract} } } -package com.iluwatar.hexagonal.eventlog { - interface LotteryNotifications { - + notifyNoWin(PlayerDetails) {abstract} - + notifyPrize(PlayerDetails, int) {abstract} - + notifyPrizeError(PlayerDetails, int) {abstract} - + notifyTicketSubmitError(PlayerDetails) {abstract} - + notifyTicketSubmitted(PlayerDetails) {abstract} - } - class LotteryNotificationsImpl { - + LotteryNotificationsImpl() - + notifyNoWin(details : PlayerDetails) - + notifyPrize(details : PlayerDetails, prizeAmount : int) - + notifyPrizeError(details : PlayerDetails, prizeAmount : int) - + notifyTicketSubmitError(details : PlayerDetails) - + notifyTicketSubmitted(details : PlayerDetails) - } -} package com.iluwatar.hexagonal { class App { - - allPlayerDetails : List {static} + App() - - getRandomPlayerDetails() : PlayerDetails {static} + main(args : String[]) {static} - - submitTickets(lotteryService : LotteryService, numTickets : int) {static} } } package com.iluwatar.hexagonal.administration { - interface LotteryAdministration { - + getAllSubmittedTickets() : Map {abstract} - + performLottery() : LotteryNumbers {abstract} - + resetLottery() {abstract} - } - class LotteryAdministrationImpl { - - bank : WireTransfers - - notifications : LotteryNotifications - - repository : LotteryTicketRepository - - service : LotteryService - + LotteryAdministrationImpl() - + getAllSubmittedTickets() : Map - + performLottery() : LotteryNumbers - + resetLottery() + class ConsoleAdministration { + + ConsoleAdministration() + + main(args : String[]) {static} + - printMainMenu() {static} + - readString(scanner : Scanner) : String {static} } } +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 StdOutEventLog { + + StdOutEventLog() + + prizeError(details : PlayerDetails, prizeAmount : int) + + ticketDidNotWin(details : PlayerDetails) + + ticketSubmitError(details : PlayerDetails) + + ticketSubmitted(details : PlayerDetails) + + ticketWon(details : PlayerDetails, prizeAmount : int) + } + class MongoEventLog { + - DEFAULT_DB : String {static} + - DEFAULT_EVENTS_COLLECTION : String {static} + - database : MongoDatabase + - eventsCollection : MongoCollection + - mongoClient : MongoClient + - stdOutEventLog : StdOutEventLog + + MongoEventLog() + + MongoEventLog(dbName : String, eventsCollectionName : String) + + connect() + + connect(dbName : String, eventsCollectionName : String) + + getEventsCollection() : MongoCollection + + getMongoClient() : MongoClient + + getMongoDatabase() : MongoDatabase + + prizeError(details : PlayerDetails, prizeAmount : int) + + ticketDidNotWin(details : PlayerDetails) + + ticketSubmitError(details : PlayerDetails) + + ticketSubmitted(details : PlayerDetails) + + ticketWon(details : PlayerDetails, prizeAmount : int) + } +} +LotteryAdministration --+ LotteryTicketCheckResult LotteryTicket --> "-playerDetails" PlayerDetails -LotteryAdministrationImpl --> "-bank" WireTransfers -App --> "-allPlayerDetails" PlayerDetails +MongoEventLog --> "-stdOutEventLog" StdOutEventLog +LotteryService --> "-wireTransfers" WireTransfers +LotteryAdministration --> "-notifications" LotteryEventLog RandomNumberGenerator ..+ PrimitiveIterator -LotteryAdministrationImpl --> "-repository" LotteryTicketRepository -LotteryAdministrationImpl --+ LotteryTicketCheckResult -LotteryServiceImpl --> "-notifications" LotteryNotifications +LotteryAdministration --> "-wireTransfers" WireTransfers +LotteryTicket --> "-id" LotteryTicketId +LotteryService --> "-notifications" LotteryEventLog +LotteryAdministration --> "-repository" LotteryTicketRepository LotteryTicket --> "-lotteryNumbers" LotteryNumbers -LotteryAdministrationImpl --> "-notifications" LotteryNotifications -LotteryServiceImpl --> "-repository" LotteryTicketRepository -LotteryServiceImpl --+ LotteryTicketCheckResult -LotteryServiceImpl --> "-bank" WireTransfers +SampleData --> "-PLAYERS" PlayerDetails +ConsoleLottery --+ LotteryTicketCheckResult RandomNumberGenerator ..+ LotteryNumbers -LotteryAdministrationImpl --> "-service" LotteryService +LotteryService --> "-repository" LotteryTicketRepository +LotteryUtils --+ LotteryTicketCheckResult LotteryTicketCheckResult --> "-checkResult" CheckResult CheckResult ..+ LotteryTicketCheckResult -LotteryTicketInMemoryRepository ..|> LotteryTicketRepository -WireTransfersImpl ..|> WireTransfers -LotteryServiceImpl ..|> LotteryService -LotteryNotificationsImpl ..|> LotteryNotifications -LotteryAdministrationImpl ..|> LotteryAdministration +MongoTicketRepository ..|> LotteryTicketRepository +MongoBank ..|> WireTransfers +InMemoryBank ..|> WireTransfers +StdOutEventLog ..|> LotteryEventLog +InMemoryTicketRepository ..|> LotteryTicketRepository +MongoEventLog ..|> LotteryEventLog @enduml \ No newline at end of file diff --git a/intercepting-filter/etc/intercepting-filter.urm.puml b/intercepting-filter/etc/intercepting-filter.urm.puml index f5bfb54e4..e3616c3ab 100644 --- a/intercepting-filter/etc/intercepting-filter.urm.puml +++ b/intercepting-filter/etc/intercepting-filter.urm.puml @@ -1,10 +1,16 @@ @startuml package com.iluwatar.intercepting.filter { - interface Filter { - + execute(Order) : String {abstract} - + getLast() : Filter {abstract} - + getNext() : Filter {abstract} - + setNext(Filter) {abstract} + class DepositFilter { + + DepositFilter() + + execute(order : Order) : String + } + class AddressFilter { + + AddressFilter() + + execute(order : Order) : String + } + class App { + + App() + + main(args : String[]) {static} } abstract class AbstractFilter { - next : Filter @@ -15,14 +21,6 @@ package com.iluwatar.intercepting.filter { + getNext() : Filter + setNext(filter : Filter) } - class ContactFilter { - + ContactFilter() - + execute(order : Order) : String - } - class OrderFilter { - + OrderFilter() - + execute(order : Order) : String - } class Order { - address : String - contactNumber : String @@ -42,47 +40,49 @@ package com.iluwatar.intercepting.filter { + setName(name : String) + setOrder(order : String) } - class AddressFilter { - + AddressFilter() - + execute(order : Order) : String - } - ~class DListener { - ~ DListener(this$0 : Target) - + actionPerformed(e : ActionEvent) - } class FilterManager { - filterChain : FilterChain + FilterManager() + addFilter(filter : Filter) + filterRequest(order : Order) : String } + class NameFilter { + + NameFilter() + + execute(order : Order) : String + } + class ContactFilter { + + ContactFilter() + + execute(order : Order) : String + } + interface Filter { + + execute(Order) : String {abstract} + + getLast() : Filter {abstract} + + getNext() : Filter {abstract} + + setNext(Filter) {abstract} + } + ~class DListener { + ~ DListener() + + actionPerformed(e : ActionEvent) + } + class OrderFilter { + + OrderFilter() + + execute(order : Order) : String + } class FilterChain { - chain : Filter + FilterChain() + addFilter(filter : Filter) + execute(order : Order) : String } - class DepositFilter { - + DepositFilter() - + execute(order : Order) : String - } - class App { - + App() - + main(args : String[]) {static} - } - class NameFilter { - + NameFilter() - + execute(order : Order) : String - } } AbstractFilter --> "-next" Filter DListener --+ Target FilterChain --> "-chain" Filter FilterManager --> "-filterChain" FilterChain +DepositFilter --|> AbstractFilter +AddressFilter --|> AbstractFilter AbstractFilter ..|> Filter +NameFilter --|> AbstractFilter ContactFilter --|> AbstractFilter OrderFilter --|> AbstractFilter -AddressFilter --|> AbstractFilter -DepositFilter --|> AbstractFilter -NameFilter --|> AbstractFilter @enduml \ No newline at end of file diff --git a/interpreter/etc/interpreter.urm.puml b/interpreter/etc/interpreter.urm.puml index bdbd369d6..dc0d83bf2 100644 --- a/interpreter/etc/interpreter.urm.puml +++ b/interpreter/etc/interpreter.urm.puml @@ -1,23 +1,5 @@ @startuml package com.iluwatar.interpreter { - abstract class Expression { - + Expression() - + interpret() : int {abstract} - + toString() : String {abstract} - } - class PlusExpression { - - leftExpression : Expression - - rightExpression : Expression - + PlusExpression(leftExpression : Expression, rightExpression : Expression) - + interpret() : int - + toString() : String - } - class App { - + App() - + getOperatorInstance(s : String, left : Expression, right : Expression) : Expression {static} - + isOperator(s : String) : boolean {static} - + main(args : String[]) {static} - } class NumberExpression { - number : int + NumberExpression(number : int) @@ -25,13 +7,6 @@ package com.iluwatar.interpreter { + interpret() : int + toString() : String } - class MultiplyExpression { - - leftExpression : Expression - - rightExpression : Expression - + MultiplyExpression(leftExpression : Expression, rightExpression : Expression) - + interpret() : int - + toString() : String - } class MinusExpression { - leftExpression : Expression - rightExpression : Expression @@ -39,12 +14,37 @@ package com.iluwatar.interpreter { + interpret() : int + toString() : String } + class App { + + App() + + getOperatorInstance(s : String, left : Expression, right : Expression) : Expression {static} + + isOperator(s : String) : boolean {static} + + main(args : String[]) {static} + } + abstract class Expression { + + Expression() + + interpret() : int {abstract} + + toString() : String {abstract} + } + class MultiplyExpression { + - leftExpression : Expression + - rightExpression : Expression + + MultiplyExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } + class PlusExpression { + - leftExpression : Expression + - rightExpression : Expression + + PlusExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } } MultiplyExpression --> "-leftExpression" Expression MinusExpression --> "-leftExpression" Expression PlusExpression --> "-leftExpression" Expression -PlusExpression --|> Expression NumberExpression --|> Expression -MultiplyExpression --|> Expression MinusExpression --|> Expression +MultiplyExpression --|> Expression +PlusExpression --|> Expression @enduml \ No newline at end of file diff --git a/iterator/etc/iterator.urm.puml b/iterator/etc/iterator.urm.puml index cbafd6595..032cd4c16 100644 --- a/iterator/etc/iterator.urm.puml +++ b/iterator/etc/iterator.urm.puml @@ -1,13 +1,17 @@ @startuml package com.iluwatar.iterator { - interface ItemIterator { - + hasNext() : boolean {abstract} - + next() : Item {abstract} - } class App { + App() + main(args : String[]) {static} } + class Item { + - name : String + - type : ItemType + + Item(type : ItemType, name : String) + + getType() : ItemType + + setType(type : ItemType) + + toString() : String + } class TreasureChestItemIterator { - chest : TreasureChest - idx : int @@ -23,13 +27,9 @@ package com.iluwatar.iterator { + getItems() : List ~ iterator(itemType : ItemType) : ItemIterator } - class Item { - - name : String - - type : ItemType - + Item(type : ItemType, name : String) - + getType() : ItemType - + setType(type : ItemType) - + toString() : String + interface ItemIterator { + + hasNext() : boolean {abstract} + + next() : Item {abstract} } enum ItemType { + ANY {static} diff --git a/layers/etc/layers.urm.puml b/layers/etc/layers.urm.puml index d67216ff8..2ec6e142e 100644 --- a/layers/etc/layers.urm.puml +++ b/layers/etc/layers.urm.puml @@ -3,62 +3,6 @@ package com.iluwatar.layers { interface View { + render() {abstract} } - class CakeBakingServiceImpl { - - context : AbstractApplicationContext - + CakeBakingServiceImpl() - + bakeNewCake(cakeInfo : CakeInfo) - + getAllCakes() : List - - getAvailableLayerEntities() : List - + getAvailableLayers() : List - - getAvailableToppingEntities() : List - + getAvailableToppings() : List - + saveNewLayer(layerInfo : CakeLayerInfo) - + saveNewTopping(toppingInfo : CakeToppingInfo) - } - interface CakeDao { - } - class CakeTopping { - - cake : Cake - - calories : int - - id : Long - - name : String - + CakeTopping() - + CakeTopping(name : String, calories : int) - + getCake() : Cake - + getCalories() : int - + getId() : Long - + getName() : String - + setCake(cake : Cake) - + setCalories(calories : int) - + setId(id : Long) - + setName(name : String) - + toString() : String - } - class CakeLayerInfo { - + calories : int - + id : Optional - + name : String - + CakeLayerInfo(id : Long, name : String, calories : int) - + CakeLayerInfo(name : String, calories : int) - + toString() : String - } - interface CakeLayerDao { - } - interface CakeToppingDao { - } - interface CakeBakingService { - + bakeNewCake(CakeInfo) {abstract} - + getAllCakes() : List {abstract} - + getAvailableLayers() : List {abstract} - + getAvailableToppings() : List {abstract} - + saveNewLayer(CakeLayerInfo) {abstract} - + saveNewTopping(CakeToppingInfo) {abstract} - } - class CakeViewImpl { - - cakeBakingService : CakeBakingService - + CakeViewImpl(cakeBakingService : CakeBakingService) - + render() - } class CakeToppingInfo { + calories : int + id : Optional @@ -67,35 +11,6 @@ package com.iluwatar.layers { + CakeToppingInfo(name : String, calories : int) + toString() : String } - class CakeInfo { - + cakeLayerInfos : List - + cakeToppingInfo : CakeToppingInfo - + id : Optional - + CakeInfo(cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) - + CakeInfo(id : Long, cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) - + calculateTotalCalories() : int - + toString() : String - } - class App { - - cakeBakingService : CakeBakingService {static} - + App() - - initializeData(cakeBakingService : CakeBakingService) {static} - + main(args : String[]) {static} - } - class Cake { - - id : Long - - layers : Set - - topping : CakeTopping - + Cake() - + addLayer(layer : CakeLayer) - + getId() : Long - + getLayers() : Set - + getTopping() : CakeTopping - + setId(id : Long) - + setLayers(layers : Set) - + setTopping(topping : CakeTopping) - + toString() : String - } class CakeLayer { - cake : Cake - calories : int @@ -113,6 +28,91 @@ package com.iluwatar.layers { + setName(name : String) + toString() : String } + class CakeLayerInfo { + + calories : int + + id : Optional + + name : String + + CakeLayerInfo(id : Long, name : String, calories : int) + + CakeLayerInfo(name : String, calories : int) + + toString() : String + } + class CakeViewImpl { + - cakeBakingService : CakeBakingService + + CakeViewImpl(cakeBakingService : CakeBakingService) + + render() + } + class CakeBakingServiceImpl { + - context : AbstractApplicationContext + + CakeBakingServiceImpl() + + bakeNewCake(cakeInfo : CakeInfo) + + getAllCakes() : List + - getAvailableLayerEntities() : List + + getAvailableLayers() : List + - getAvailableToppingEntities() : List + + getAvailableToppings() : List + + saveNewLayer(layerInfo : CakeLayerInfo) + + saveNewTopping(toppingInfo : CakeToppingInfo) + } + class CakeTopping { + - cake : Cake + - calories : int + - id : Long + - name : String + + CakeTopping() + + CakeTopping(name : String, calories : int) + + getCake() : Cake + + getCalories() : int + + getId() : Long + + getName() : String + + setCake(cake : Cake) + + setCalories(calories : int) + + setId(id : Long) + + setName(name : String) + + toString() : String + } + class Cake { + - id : Long + - layers : Set + - topping : CakeTopping + + Cake() + + addLayer(layer : CakeLayer) + + getId() : Long + + getLayers() : Set + + getTopping() : CakeTopping + + setId(id : Long) + + setLayers(layers : Set) + + setTopping(topping : CakeTopping) + + toString() : String + } + interface CakeToppingDao { + } + interface CakeBakingService { + + bakeNewCake(CakeInfo) {abstract} + + getAllCakes() : List {abstract} + + getAvailableLayers() : List {abstract} + + getAvailableToppings() : List {abstract} + + saveNewLayer(CakeLayerInfo) {abstract} + + saveNewTopping(CakeToppingInfo) {abstract} + } + class App { + - cakeBakingService : CakeBakingService {static} + + App() + - initializeData(cakeBakingService : CakeBakingService) {static} + + main(args : String[]) {static} + } + interface CakeDao { + } + interface CakeLayerDao { + } + class CakeInfo { + + cakeLayerInfos : List + + cakeToppingInfo : CakeToppingInfo + + id : Optional + + CakeInfo(cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) + + CakeInfo(id : Long, cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) + + calculateTotalCalories() : int + + toString() : String + } } CakeViewImpl --> "-cakeBakingService" CakeBakingService CakeInfo --> "-cakeToppingInfo" CakeToppingInfo @@ -120,6 +120,6 @@ CakeInfo --> "-cakeLayerInfos" CakeLayerInfo App --> "-cakeBakingService" CakeBakingService CakeLayer --> "-cake" Cake Cake --> "-topping" CakeTopping -CakeBakingServiceImpl ..|> CakeBakingService CakeViewImpl ..|> View +CakeBakingServiceImpl ..|> CakeBakingService @enduml \ No newline at end of file diff --git a/lazy-loading/etc/lazy-loading.urm.puml b/lazy-loading/etc/lazy-loading.urm.puml index 96c427553..80192160a 100644 --- a/lazy-loading/etc/lazy-loading.urm.puml +++ b/lazy-loading/etc/lazy-loading.urm.puml @@ -2,20 +2,24 @@ package com.iluwatar.lazy.loading { ~class HeavyFactory { - heavyInstance : Heavy - ~ HeavyFactory(this$0 : Java8Holder) + ~ HeavyFactory() + get() : Heavy } - class HolderNaive { + class App { + + App() + + main(args : String[]) {static} + } + class HolderThreadSafe { - heavy : Heavy - + HolderNaive() + + HolderThreadSafe() + getHeavy() : Heavy } class Heavy { + Heavy() } - class HolderThreadSafe { + class HolderNaive { - heavy : Heavy - + HolderThreadSafe() + + HolderNaive() + getHeavy() : Heavy } class Java8Holder { @@ -24,12 +28,8 @@ package com.iluwatar.lazy.loading { - createAndCacheHeavy() : Heavy + getHeavy() : Heavy } - class App { - + App() - + main(args : String[]) {static} - } } -HolderThreadSafe --> "-heavy" Heavy HolderNaive --> "-heavy" Heavy +HolderThreadSafe --> "-heavy" Heavy HeavyFactory --> "-heavyInstance" Heavy @enduml \ No newline at end of file diff --git a/mediator/etc/mediator.urm.puml b/mediator/etc/mediator.urm.puml index 0b3baab5a..330e024ab 100644 --- a/mediator/etc/mediator.urm.puml +++ b/mediator/etc/mediator.urm.puml @@ -1,24 +1,20 @@ @startuml package com.iluwatar.mediator { - class App { - + App() - + main(args : String[]) {static} - } - class Hobbit { - + Hobbit() - + toString() : String + interface Party { + + act(PartyMember, Action) {abstract} + + addMember(PartyMember) {abstract} } interface PartyMember { + act(Action) {abstract} + joinedParty(Party) {abstract} + partyAction(Action) {abstract} } - interface Party { - + act(PartyMember, Action) {abstract} - + addMember(PartyMember) {abstract} + class Rogue { + + Rogue() + + toString() : String } - class Wizard { - + Wizard() + class Hunter { + + Hunter() + toString() : String } class PartyImpl { @@ -27,12 +23,12 @@ package com.iluwatar.mediator { + act(actor : PartyMember, action : Action) + addMember(member : PartyMember) } - class Hunter { - + Hunter() + class Hobbit { + + Hobbit() + toString() : String } - class Rogue { - + Rogue() + class Wizard { + + Wizard() + toString() : String } abstract class PartyMemberBase { @@ -43,6 +39,10 @@ package com.iluwatar.mediator { + partyAction(action : Action) + toString() : String {abstract} } + class App { + + App() + + main(args : String[]) {static} + } enum Action { + ENEMY {static} + GOLD {static} @@ -59,10 +59,10 @@ package com.iluwatar.mediator { } PartyImpl --> "-members" PartyMember PartyMemberBase --> "-party" Party +Rogue --|> PartyMemberBase +Hunter --|> PartyMemberBase +PartyImpl ..|> Party Hobbit --|> PartyMemberBase Wizard --|> PartyMemberBase -PartyImpl ..|> Party -Hunter --|> PartyMemberBase -Rogue --|> PartyMemberBase PartyMemberBase ..|> PartyMember @enduml \ No newline at end of file diff --git a/memento/etc/memento.urm.puml b/memento/etc/memento.urm.puml index aa63b4ebe..316d4047d 100644 --- a/memento/etc/memento.urm.puml +++ b/memento/etc/memento.urm.puml @@ -1,17 +1,5 @@ @startuml package com.iluwatar.memento { - class Star { - - ageYears : int - - massTons : int - - type : StarType - + Star(startType : StarType, startAge : int, startMass : int) - ~ getMemento() : StarMemento - ~ setMemento(memento : StarMemento) - + timePasses() - + toString() : String - } - interface StarMemento { - } -class StarMementoInternal { - ageYears : int - massTons : int @@ -28,6 +16,18 @@ package com.iluwatar.memento { + App() + main(args : String[]) {static} } + interface StarMemento { + } + class Star { + - ageYears : int + - massTons : int + - type : StarType + + Star(startType : StarType, startAge : int, startMass : int) + ~ getMemento() : StarMemento + ~ setMemento(memento : StarMemento) + + timePasses() + + toString() : String + } enum StarType { + DEAD {static} + RED_GIANT {static} diff --git a/model-view-controller/etc/model-view-controller.urm.puml b/model-view-controller/etc/model-view-controller.urm.puml index f8137bdae..ad979fe0e 100644 --- a/model-view-controller/etc/model-view-controller.urm.puml +++ b/model-view-controller/etc/model-view-controller.urm.puml @@ -13,14 +13,6 @@ package com.iluwatar.model.view.controller { + setNourishment(nourishment : Nourishment) + toString() : String } - class App { - + App() - + main(args : String[]) {static} - } - class GiantView { - + GiantView() - + displayGiant(giant : GiantModel) - } class GiantController { - giant : GiantModel - view : GiantView @@ -33,6 +25,23 @@ package com.iluwatar.model.view.controller { + setNourishment(nourishment : Nourishment) + updateView() } + class GiantView { + + GiantView() + + displayGiant(giant : GiantModel) + } + class App { + + App() + + main(args : String[]) {static} + } + enum Health { + + DEAD {static} + + HEALTHY {static} + + WOUNDED {static} + - title : String + + toString() : String + + valueOf(name : String) : Health {static} + + values() : Health[] {static} + } enum Nourishment { + HUNGRY {static} + SATURATED {static} @@ -51,15 +60,6 @@ package com.iluwatar.model.view.controller { + valueOf(name : String) : Fatigue {static} + values() : Fatigue[] {static} } - enum Health { - + DEAD {static} - + HEALTHY {static} - + WOUNDED {static} - - title : String - + toString() : String - + valueOf(name : String) : Health {static} - + values() : Health[] {static} - } } GiantModel --> "-nourishment" Nourishment GiantController --> "-giant" GiantModel diff --git a/model-view-presenter/etc/model-view-presenter.urm.puml b/model-view-presenter/etc/model-view-presenter.urm.puml index 64bcfba32..0cec653e4 100644 --- a/model-view-presenter/etc/model-view-presenter.urm.puml +++ b/model-view-presenter/etc/model-view-presenter.urm.puml @@ -1,42 +1,5 @@ @startuml package com.iluwatar.model.view.presenter { - class FileLoader { - - fileName : String - - loaded : boolean - + FileLoader() - + fileExists() : boolean - + getFileName() : String - + isLoaded() : boolean - + loadData() : String - + setFileName(fileName : String) - } - class FileSelectorJFrame { - - area : JTextArea - - cancel : JButton - - contents : JLabel - - fileName : String - - info : JLabel - - input : JTextField - - ok : JButton - - panel : JPanel - - presenter : FileSelectorPresenter - - serialVersionUID : long {static} - + FileSelectorJFrame() - + actionPerformed(e : ActionEvent) - + close() - + displayData(data : String) - + getFileName() : String - + getPresenter() : FileSelectorPresenter - + isOpened() : boolean - + open() - + setFileName(name : String) - + setPresenter(presenter : FileSelectorPresenter) - + showMessage(message : String) - } - class App { - + App() - + main(args : String[]) {static} - } interface FileSelectorView { + close() {abstract} + displayData(String) {abstract} @@ -67,6 +30,16 @@ package com.iluwatar.model.view.presenter { + setPresenter(presenter : FileSelectorPresenter) + showMessage(message : String) } + class FileLoader { + - fileName : String + - loaded : boolean + + FileLoader() + + fileExists() : boolean + + getFileName() : String + + isLoaded() : boolean + + loadData() : String + + setFileName(fileName : String) + } class FileSelectorPresenter { - loader : FileLoader - view : FileSelectorView @@ -77,11 +50,38 @@ package com.iluwatar.model.view.presenter { + setLoader(loader : FileLoader) + start() } + class App { + + App() + + main(args : String[]) {static} + } + class FileSelectorJFrame { + - area : JTextArea + - cancel : JButton + - contents : JLabel + - fileName : String + - info : JLabel + - input : JTextField + - ok : JButton + - panel : JPanel + - presenter : FileSelectorPresenter + - serialVersionUID : long {static} + + FileSelectorJFrame() + + actionPerformed(e : ActionEvent) + + close() + + displayData(data : String) + + getFileName() : String + + getPresenter() : FileSelectorPresenter + + isOpened() : boolean + + open() + + setFileName(name : String) + + setPresenter(presenter : FileSelectorPresenter) + + showMessage(message : String) + } } -FileSelectorStub --> "-presenter" FileSelectorPresenter FileSelectorJFrame --> "-presenter" FileSelectorPresenter +FileSelectorStub --> "-presenter" FileSelectorPresenter FileSelectorPresenter --> "-loader" FileLoader FileSelectorPresenter --> "-view" FileSelectorView -FileSelectorJFrame ..|> FileSelectorView FileSelectorStub ..|> FileSelectorView +FileSelectorJFrame ..|> FileSelectorView @enduml \ No newline at end of file diff --git a/monostate/etc/monostate.urm.puml b/monostate/etc/monostate.urm.puml index 3c09bb4ed..6574bcad1 100644 --- a/monostate/etc/monostate.urm.puml +++ b/monostate/etc/monostate.urm.puml @@ -1,5 +1,13 @@ @startuml package com.iluwatar.monostate { + class App { + + App() + + main(args : String[]) {static} + } + class Request { + + value : String + + Request(value : String) + } class LoadBalancer { - id : int {static} - lastServedId : int {static} @@ -10,14 +18,6 @@ package com.iluwatar.monostate { + getNoOfServers() : int + serverRequest(request : Request) } - class App { - + App() - + main(args : String[]) {static} - } - class Request { - + value : String - + Request(value : String) - } class Server { + host : String + id : int diff --git a/mute-idiom/etc/mute-idiom.urm.puml b/mute-idiom/etc/mute-idiom.urm.puml index d4efc2db1..c992773f5 100644 --- a/mute-idiom/etc/mute-idiom.urm.puml +++ b/mute-idiom/etc/mute-idiom.urm.puml @@ -1,6 +1,7 @@ @startuml package com.iluwatar.mute { - interface Resource { + interface CheckedRunnable { + + run() {abstract} } class App { + App() @@ -16,8 +17,7 @@ package com.iluwatar.mute { + loggedMute(runnable : CheckedRunnable) {static} + mute(runnable : CheckedRunnable) {static} } - interface CheckedRunnable { - + run() {abstract} + interface Resource { } } @enduml \ No newline at end of file diff --git a/mutex/etc/mutex.urm.puml b/mutex/etc/mutex.urm.puml index 24ea83630..68b96d668 100644 --- a/mutex/etc/mutex.urm.puml +++ b/mutex/etc/mutex.urm.puml @@ -1,5 +1,11 @@ @startuml package com.iluwatar.mutex { + class Jar { + - beans : int + - lock : Lock + + Jar(beans : int, lock : Lock) + + takeBean() : boolean + } interface Lock { + acquire() {abstract} + release() {abstract} @@ -11,12 +17,6 @@ package com.iluwatar.mutex { + getOwner() : Object + release() } - class Jar { - - beans : int - - lock : Lock - + Jar(beans : int, lock : Lock) - + takeBean() : boolean - } class App { + App() + main(args : String[]) {static} diff --git a/naked-objects/etc/naked-objects-dom.urm.puml b/naked-objects/etc/naked-objects-dom.urm.puml index ea32b5787..6662a560a 100644 --- a/naked-objects/etc/naked-objects-dom.urm.puml +++ b/naked-objects/etc/naked-objects-dom.urm.puml @@ -23,58 +23,13 @@ package domainapp.dom.modules.simple { } class SimpleObject { - container : DomainObjectContainer - - dnFieldFlags : byte[] {static} - - dnFieldNames : String[] {static} - - dnFieldTypes : Class[] {static} - # dnFlags : byte - - dnInheritedFieldCount : int {static} - - dnPersistableSuperclass : Class {static} - # dnStateManager : StateManager - name : String + SimpleObject() - + ___dn$loadClass(className : String) : Class {static} - - __dnFieldFlagsInit() : byte[] {static} - - __dnFieldNamesInit() : String[] {static} - - __dnFieldTypesInit() : Class[] {static} - # __dnGetInheritedFieldCount() : int {static} - - __dnPersistableSuperclassInit() : Class {static} + compareTo(other : SimpleObject) : int + default0UpdateName() : String - # dnCopyField(obj : SimpleObject, index : int) - + dnCopyFields(obj : Object, indices : int[]) - + dnCopyKeyFieldsFromObjectId(fc : ObjectIdFieldConsumer, oid : Object) - # dnCopyKeyFieldsFromObjectId(oid : Object) - + dnCopyKeyFieldsToObjectId(fs : ObjectIdFieldSupplier, oid : Object) - + dnCopyKeyFieldsToObjectId(oid : Object) - + dnGetExecutionContext() : ExecutionContextReference - # dnGetManagedFieldCount() : int {static} - + dnGetObjectId() : Object - + dnGetTransactionalObjectId() : Object - + dnGetVersion() : Object - + dnGetname() : String - + dnIsDeleted() : boolean - + dnIsDetached() : boolean - + dnIsDirty() : boolean - + dnIsNew() : boolean - + dnIsPersistent() : boolean - + dnIsTransactional() : boolean - + dnMakeDirty(fieldName : String) - + dnNewInstance(sm : StateManager) : Persistable - + dnNewInstance(sm : StateManager, obj : Object) : Persistable - + dnNewObjectIdInstance() : Object - + dnNewObjectIdInstance(key : Object) : Object - # dnPreSerialize() - + dnProvideField(index : int) - + dnProvideFields(indices : int[]) - + dnReplaceField(index : int) - + dnReplaceFields(indices : int[]) - + dnReplaceFlags() - + dnReplaceStateManager(sm : StateManager) - + dnSetname(name : String) - - dnSuperClone() : Object + getName() : String + getVersionSequence() : Long - + setName(val : String) + + setName(name : String) + title() : TranslatableString + updateName(name : String) : SimpleObject + validateUpdateName(name : String) : TranslatableString diff --git a/naked-objects/etc/naked-objects-fixture.urm.puml b/naked-objects/etc/naked-objects-fixture.urm.puml index 65c44410a..21e38d710 100644 --- a/naked-objects/etc/naked-objects-fixture.urm.puml +++ b/naked-objects/etc/naked-objects-fixture.urm.puml @@ -1,16 +1,16 @@ @startuml package domainapp.dom.app.homepage { + class HomePageService { + ~ container : DomainObjectContainer + + HomePageService() + + homePage() : HomePageViewModel + } class HomePageViewModel { ~ simpleObjects : SimpleObjects + HomePageViewModel() + getObjects() : List + title() : String } - class HomePageService { - ~ container : DomainObjectContainer - + HomePageService() - + homePage() : HomePageViewModel - } } package domainapp.dom.modules.simple { class SimpleObject { diff --git a/naked-objects/etc/naked-objects-integtests.urm.puml b/naked-objects/etc/naked-objects-integtests.urm.puml index 1f2dfc4c2..65c44410a 100644 --- a/naked-objects/etc/naked-objects-integtests.urm.puml +++ b/naked-objects/etc/naked-objects-integtests.urm.puml @@ -1,26 +1,18 @@ @startuml package domainapp.dom.app.homepage { - class HomePageService { - ~ container : DomainObjectContainer - + HomePageService() - + homePage() : HomePageViewModel - } class HomePageViewModel { ~ simpleObjects : SimpleObjects + HomePageViewModel() + getObjects() : List + title() : String } + class HomePageService { + ~ container : DomainObjectContainer + + HomePageService() + + homePage() : HomePageViewModel + } } package domainapp.dom.modules.simple { - class SimpleObjects { - ~ container : DomainObjectContainer - + SimpleObjects() - + create(name : String) : SimpleObject - + findByName(name : String) : List - + listAll() : List - + title() : TranslatableString - } class SimpleObject { - container : DomainObjectContainer - dnFieldFlags : byte[] {static} @@ -79,6 +71,14 @@ package domainapp.dom.modules.simple { + updateName(name : String) : SimpleObject + validateUpdateName(name : String) : TranslatableString } + class SimpleObjects { + ~ container : DomainObjectContainer + + SimpleObjects() + + create(name : String) : SimpleObject + + findByName(name : String) : List + + listAll() : List + + title() : TranslatableString + } } package domainapp.fixture { class DomainAppFixturesProvider { diff --git a/null-object/etc/null-object.urm.puml b/null-object/etc/null-object.urm.puml index d0b2936c5..bd4f8446e 100644 --- a/null-object/etc/null-object.urm.puml +++ b/null-object/etc/null-object.urm.puml @@ -1,22 +1,5 @@ @startuml package com.iluwatar.nullobject { - class NullNode { - - instance : NullNode {static} - - NullNode() - + getInstance() : NullNode {static} - + getLeft() : Node - + getName() : String - + getRight() : Node - + getTreeSize() : int - + walk() - } - interface Node { - + getLeft() : Node {abstract} - + getName() : String {abstract} - + getRight() : Node {abstract} - + getTreeSize() : int {abstract} - + walk() {abstract} - } class App { + App() + main(args : String[]) {static} @@ -32,9 +15,26 @@ package com.iluwatar.nullobject { + getTreeSize() : int + walk() } + interface Node { + + getLeft() : Node {abstract} + + getName() : String {abstract} + + getRight() : Node {abstract} + + getTreeSize() : int {abstract} + + walk() {abstract} + } + class NullNode { + - instance : NullNode {static} + - NullNode() + + getInstance() : NullNode {static} + + getLeft() : Node + + getName() : String + + getRight() : Node + + getTreeSize() : int + + walk() + } } NullNode --> "-instance" NullNode NodeImpl --> "-left" Node -NullNode ..|> Node NodeImpl ..|> Node +NullNode ..|> Node @enduml \ No newline at end of file diff --git a/object-pool/etc/object-pool.urm.puml b/object-pool/etc/object-pool.urm.puml index 9df1081d3..caf0b6d7e 100644 --- a/object-pool/etc/object-pool.urm.puml +++ b/object-pool/etc/object-pool.urm.puml @@ -1,5 +1,9 @@ @startuml package com.iluwatar.object.pool { + class OliphauntPool { + + OliphauntPool() + # create() : Oliphaunt + } class Oliphaunt { - counter : int {static} - id : int @@ -7,14 +11,6 @@ package com.iluwatar.object.pool { + getId() : int + toString() : String } - class OliphauntPool { - + OliphauntPool() - # create() : Oliphaunt - } - class App { - + App() - + main(args : String[]) {static} - } abstract class ObjectPool { - available : HashSet - inUse : HashSet @@ -24,6 +20,10 @@ package com.iluwatar.object.pool { # create() : T {abstract} + toString() : String } + class App { + + App() + + main(args : String[]) {static} + } } OliphauntPool --|> ObjectPool @enduml \ No newline at end of file diff --git a/observer/etc/observer.urm.puml b/observer/etc/observer.urm.puml index 33485d731..e9a8f7b9b 100644 --- a/observer/etc/observer.urm.puml +++ b/observer/etc/observer.urm.puml @@ -4,9 +4,12 @@ package com.iluwatar.observer { + Orcs() + update(currentWeather : WeatherType) } - class Hobbits { - + Hobbits() - + update(currentWeather : WeatherType) + interface WeatherObserver { + + update(WeatherType) {abstract} + } + class App { + + App() + + main(args : String[]) {static} } class Weather { - currentWeather : WeatherType @@ -17,12 +20,9 @@ package com.iluwatar.observer { + removeObserver(obs : WeatherObserver) + timePasses() } - class App { - + App() - + main(args : String[]) {static} - } - interface WeatherObserver { - + update(WeatherType) {abstract} + class Hobbits { + + Hobbits() + + update(currentWeather : WeatherType) } enum WeatherType { + COLD {static} @@ -41,6 +41,11 @@ package com.iluwatar.observer.generic { } interface Race { } + class GWeather { + - currentWeather : WeatherType + + GWeather() + + timePasses() + } abstract class Observable, A> { # observers : List> + Observable, A>() @@ -48,26 +53,21 @@ package com.iluwatar.observer.generic { + notifyObservers(argument : A) + removeObserver(observer : O extends Observer) } - class GWeather { - - currentWeather : WeatherType - + GWeather() - + timePasses() - } - interface Observer, O extends Observer, A> { - + update(S extends Observable, A) {abstract} - } class GHobbits { + GHobbits() + update(weather : GWeather, weatherType : WeatherType) } + interface Observer, O extends Observer, A> { + + update(S extends Observable, A) {abstract} + } } Weather --> "-currentWeather" WeatherType GWeather --> "-currentWeather" WeatherType Weather --> "-observers" WeatherObserver GOrcs ..|> Race Orcs ..|> WeatherObserver -Hobbits ..|> WeatherObserver Race --|> Observer GWeather --|> Observable GHobbits ..|> Race +Hobbits ..|> WeatherObserver @enduml \ No newline at end of file diff --git a/poison-pill/etc/poison-pill.urm.puml b/poison-pill/etc/poison-pill.urm.puml index 58f9eb937..f05c40692 100644 --- a/poison-pill/etc/poison-pill.urm.puml +++ b/poison-pill/etc/poison-pill.urm.puml @@ -1,5 +1,8 @@ @startuml package com.iluwatar.poison.pill { + interface MqPublishPoint { + + put(Message) {abstract} + } interface Message { + POISON_PILL : Message {static} + addHeader(Headers, String) {abstract} @@ -12,21 +15,7 @@ package com.iluwatar.poison.pill { + App() + main(args : String[]) {static} } - class SimpleMessage { - - body : String - - headers : Map - + SimpleMessage() - + addHeader(header : Headers, value : String) - + getBody() : String - + getHeader(header : Headers) : String - + getHeaders() : Map - + setBody(body : String) - } - class SimpleMessageQueue { - - queue : BlockingQueue - + SimpleMessageQueue(bound : int) - + put(msg : Message) - + take() : Message + interface MessageQueue { } class Producer { - isStopped : boolean @@ -36,19 +25,30 @@ package com.iluwatar.poison.pill { + send(body : String) + stop() } - interface MqSubscribePoint { - + take() : Message {abstract} - } class Consumer { - name : String - queue : MqSubscribePoint + Consumer(name : String, queue : MqSubscribePoint) + consume() } - interface MessageQueue { + class SimpleMessageQueue { + - queue : BlockingQueue + + SimpleMessageQueue(bound : int) + + put(msg : Message) + + take() : Message } - interface MqPublishPoint { - + put(Message) {abstract} + interface MqSubscribePoint { + + take() : Message {abstract} + } + class SimpleMessage { + - body : String + - headers : Map + + SimpleMessage() + + addHeader(header : Headers, value : String) + + getBody() : String + + getHeader(header : Headers) : String + + getHeaders() : Map + + setBody(body : String) } enum Headers { + DATE {static} @@ -65,8 +65,8 @@ SimpleMessage --+ Message Producer --+ Message Message --> "-POISON_PILL" Message Consumer --+ Message -SimpleMessage ..|> Message -SimpleMessageQueue ..|> MessageQueue MessageQueue --|> MqPublishPoint MessageQueue --|> MqSubscribePoint +SimpleMessageQueue ..|> MessageQueue +SimpleMessage ..|> Message @enduml \ No newline at end of file diff --git a/pom.xml b/pom.xml index b1ae7d811..fcf1671c8 100644 --- a/pom.xml +++ b/pom.xml @@ -282,6 +282,25 @@ + + + + com.github.markusmo3.urm + + + urm-maven-plugin + + + [1.4.1,) + + + map + + + + + + diff --git a/private-class-data/etc/private-class-data.urm.puml b/private-class-data/etc/private-class-data.urm.puml index 0edc2c1a8..ad35c0bdd 100644 --- a/private-class-data/etc/private-class-data.urm.puml +++ b/private-class-data/etc/private-class-data.urm.puml @@ -1,18 +1,5 @@ @startuml package com.iluwatar.privateclassdata { - class Stew { - - numCarrots : int - - numMeat : int - - numPeppers : int - - numPotatoes : int - + Stew(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) - + mix() - + taste() - } - class App { - + App() - + main(args : String[]) {static} - } class StewData { - numCarrots : int - numMeat : int @@ -24,6 +11,19 @@ package com.iluwatar.privateclassdata { + getNumPeppers() : int + getNumPotatoes() : int } + class App { + + App() + + main(args : String[]) {static} + } + class Stew { + - numCarrots : int + - numMeat : int + - numPeppers : int + - numPotatoes : int + + Stew(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) + + mix() + + taste() + } class ImmutableStew { - data : StewData + ImmutableStew(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) diff --git a/producer-consumer/etc/producer-consumer.urm.puml b/producer-consumer/etc/producer-consumer.urm.puml index 9a6748552..8b793d75b 100644 --- a/producer-consumer/etc/producer-consumer.urm.puml +++ b/producer-consumer/etc/producer-consumer.urm.puml @@ -1,5 +1,22 @@ @startuml package com.iluwatar.producer.consumer { + class Consumer { + - name : String + - queue : ItemQueue + + Consumer(name : String, queue : ItemQueue) + + consume() + } + class Item { + - id : int + - producer : String + + Item(producer : String, id : int) + + getId() : int + + getProducer() : String + } + class App { + + App() + + main(args : String[]) {static} + } class Producer { - itemId : int - name : String @@ -13,23 +30,6 @@ package com.iluwatar.producer.consumer { + put(item : Item) + take() : Item } - class Item { - - id : int - - producer : String - + Item(producer : String, id : int) - + getId() : int - + getProducer() : String - } - class App { - + App() - + main(args : String[]) {static} - } - class Consumer { - - name : String - - queue : ItemQueue - + Consumer(name : String, queue : ItemQueue) - + consume() - } } Consumer --> "-queue" ItemQueue Producer --> "-queue" ItemQueue diff --git a/promise/etc/promise.urm.puml b/promise/etc/promise.urm.puml index d97871411..cd6e73252 100644 --- a/promise/etc/promise.urm.puml +++ b/promise/etc/promise.urm.puml @@ -24,12 +24,18 @@ package com.iluwatar.promise { - ConsumeAction(src : Promise, dest : Promise, action : Consumer) + run() } - -class TransformAction { - - dest : Promise - - func : Function - - src : Promise - - TransformAction(src : Promise, dest : Promise, func : Function) - + run() + class Promise { + - exceptionHandler : Consumer + - fulfillmentAction : Runnable + + Promise() + + fulfill(value : T) + + fulfillExceptionally(exception : Exception) + + fulfillInAsync(task : Callable, executor : Executor) : Promise + - handleException(exception : Exception) + + onError(exceptionHandler : Consumer) : Promise + - postFulfillment() + + thenAccept(action : Consumer) : Promise + + thenApply(func : Function) : Promise } class App { - DEFAULT_URL : String {static} @@ -47,18 +53,12 @@ package com.iluwatar.promise { - stop() - taskCompleted() } - class Promise { - - exceptionHandler : Consumer - - fulfillmentAction : Runnable - + Promise() - + fulfill(value : T) - + fulfillExceptionally(exception : Exception) - + fulfillInAsync(task : Callable, executor : Executor) : Promise - - handleException(exception : Exception) - + onError(exceptionHandler : Consumer) : Promise - - postFulfillment() - + thenAccept(action : Consumer) : Promise - + thenApply(func : Function) : Promise + -class TransformAction { + - dest : Promise + - func : Function + - src : Promise + - TransformAction(src : Promise, dest : Promise, func : Function) + + run() } class Utility { + Utility() diff --git a/property/etc/property.urm.puml b/property/etc/property.urm.puml index 7c90edccc..6ff0e5c52 100644 --- a/property/etc/property.urm.puml +++ b/property/etc/property.urm.puml @@ -1,5 +1,15 @@ @startuml package com.iluwatar.property { + class App { + + App() + + main(args : String[]) {static} + } + interface Prototype { + + get(Stats) : Integer {abstract} + + has(Stats) : boolean {abstract} + + remove(Stats) {abstract} + + set(Stats, Integer) {abstract} + } class Character { - name : String - properties : Map @@ -16,15 +26,12 @@ package com.iluwatar.property { + toString() : String + type() : Type } - interface Prototype { - + get(Stats) : Integer {abstract} - + has(Stats) : boolean {abstract} - + remove(Stats) {abstract} - + set(Stats, Integer) {abstract} - } - class App { - + App() - + main(args : String[]) {static} + enum Type { + + MAGE {static} + + ROGUE {static} + + WARRIOR {static} + + valueOf(name : String) : Type {static} + + values() : Type[] {static} } enum Stats { + AGILITY {static} @@ -38,13 +45,6 @@ package com.iluwatar.property { + valueOf(name : String) : Stats {static} + values() : Stats[] {static} } - enum Type { - + MAGE {static} - + ROGUE {static} - + WARRIOR {static} - + valueOf(name : String) : Type {static} - + values() : Type[] {static} - } } App --+ Character Character --> "-prototype" Prototype diff --git a/prototype/etc/prototype.urm.puml b/prototype/etc/prototype.urm.puml index 7bfc00e15..7ab26dd1b 100644 --- a/prototype/etc/prototype.urm.puml +++ b/prototype/etc/prototype.urm.puml @@ -1,59 +1,42 @@ @startuml package com.iluwatar.prototype { - interface HeroFactory { - + createBeast() : Beast {abstract} - + createMage() : Mage {abstract} - + createWarlord() : Warlord {abstract} + class OrcWarlord { + + OrcWarlord() + + clone() : Warlord + + toString() : String } class OrcBeast { + OrcBeast() + clone() : Beast + toString() : String } - abstract class Mage { - + Mage() - + clone() : Mage {abstract} - } - class HeroFactoryImpl { - - beast : Beast - - mage : Mage - - warlord : Warlord - + HeroFactoryImpl(mage : Mage, warlord : Warlord, beast : Beast) - + createBeast() : Beast - + createMage() : Mage - + createWarlord() : Warlord + abstract class Beast { + + Beast() + + clone() : Beast {abstract} } class ElfMage { + ElfMage() + clone() : Mage + toString() : String } + abstract class Mage { + + Mage() + + clone() : Mage {abstract} + } abstract class Prototype { + Prototype() + clone() : Object {abstract} } - class App { - + App() - + main(args : String[]) {static} - } - abstract class Warlord { - + Warlord() - + clone() : Warlord {abstract} - } - class OrcWarlord { - + OrcWarlord() - + clone() : Warlord - + toString() : String + interface HeroFactory { + + createBeast() : Beast {abstract} + + createMage() : Mage {abstract} + + createWarlord() : Warlord {abstract} } class ElfWarlord { + ElfWarlord() + clone() : Warlord + toString() : String } - abstract class Beast { - + Beast() - + clone() : Beast {abstract} - } class OrcMage { + OrcMage() + clone() : Mage @@ -64,18 +47,35 @@ package com.iluwatar.prototype { + clone() : Beast + toString() : String } + abstract class Warlord { + + Warlord() + + clone() : Warlord {abstract} + } + class HeroFactoryImpl { + - beast : Beast + - mage : Mage + - warlord : Warlord + + HeroFactoryImpl(mage : Mage, warlord : Warlord, beast : Beast) + + createBeast() : Beast + + createMage() : Mage + + createWarlord() : Warlord + } + class App { + + App() + + main(args : String[]) {static} + } } HeroFactoryImpl --> "-beast" Beast HeroFactoryImpl --> "-warlord" Warlord HeroFactoryImpl --> "-mage" Mage -OrcBeast --|> Beast -Mage --|> Prototype -HeroFactoryImpl ..|> HeroFactory -ElfMage --|> Mage -Warlord --|> Prototype OrcWarlord --|> Warlord -ElfWarlord --|> Warlord +OrcBeast --|> Beast Beast --|> Prototype +ElfMage --|> Mage +Mage --|> Prototype +ElfWarlord --|> Warlord OrcMage --|> Mage ElfBeast --|> Beast +Warlord --|> Prototype +HeroFactoryImpl ..|> HeroFactory @enduml \ No newline at end of file diff --git a/proxy/etc/proxy.urm.puml b/proxy/etc/proxy.urm.puml index 4203174de..1dc58087c 100644 --- a/proxy/etc/proxy.urm.puml +++ b/proxy/etc/proxy.urm.puml @@ -1,5 +1,11 @@ @startuml package com.iluwatar.proxy { + class WizardTowerProxy { + - NUM_WIZARDS_ALLOWED : int {static} + - numWizards : int + + WizardTowerProxy() + + enter(wizard : Wizard) + } class WizardTower { + WizardTower() + enter(wizard : Wizard) @@ -8,12 +14,6 @@ package com.iluwatar.proxy { + App() + main(args : String[]) {static} } - class WizardTowerProxy { - - NUM_WIZARDS_ALLOWED : int {static} - - numWizards : int - + WizardTowerProxy() - + enter(wizard : Wizard) - } class Wizard { - name : String + Wizard(name : String) diff --git a/reactor/etc/reactor.urm.puml b/reactor/etc/reactor.urm.puml index 302f2663c..ecf2f40f7 100644 --- a/reactor/etc/reactor.urm.puml +++ b/reactor/etc/reactor.urm.puml @@ -1,5 +1,24 @@ @startuml package com.iluwatar.reactor.app { + class App { + - channels : List + - dispatcher : Dispatcher + - reactor : NioReactor + + App(dispatcher : Dispatcher) + + main(args : String[]) {static} + + start() + + stop() + - tcpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel + - udpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel + } + class LoggingHandler { + - ACK : byte[] {static} + + LoggingHandler() + - doLogging(data : ByteBuffer) {static} + + handleChannelRead(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + - sendReply(channel : AbstractNioChannel, incomingPacket : DatagramPacket, key : SelectionKey) {static} + - sendReply(channel : AbstractNioChannel, key : SelectionKey) {static} + } ~class TcpLoggingClient { - clientName : String - serverPort : int @@ -13,14 +32,6 @@ package com.iluwatar.reactor.app { + UdpLoggingClient(clientName : String, port : int) + run() } - class LoggingHandler { - - ACK : byte[] {static} - + LoggingHandler() - - doLogging(data : ByteBuffer) {static} - + handleChannelRead(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) - - sendReply(channel : AbstractNioChannel, incomingPacket : DatagramPacket, key : SelectionKey) {static} - - sendReply(channel : AbstractNioChannel, key : SelectionKey) {static} - } class AppClient { - service : ExecutorService + AppClient() @@ -29,58 +40,8 @@ package com.iluwatar.reactor.app { + start() + stop() } - class App { - - channels : List - - dispatcher : Dispatcher - - reactor : NioReactor - + App(dispatcher : Dispatcher) - + main(args : String[]) {static} - + start() - + stop() - - tcpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel - - udpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel - } } package com.iluwatar.reactor.framework { - interface Dispatcher { - + onChannelReadEvent(AbstractNioChannel, Object, SelectionKey) {abstract} - + stop() {abstract} - } - class SameThreadDispatcher { - + SameThreadDispatcher() - + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) - + stop() - } - class ThreadPoolDispatcher { - - executorService : ExecutorService - + ThreadPoolDispatcher(poolSize : int) - + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) - + stop() - } - interface ChannelHandler { - + handleChannelRead(AbstractNioChannel, Object, SelectionKey) {abstract} - } - class NioDatagramChannel { - - port : int - + NioDatagramChannel(port : int, handler : ChannelHandler) - + bind() - # doWrite(pendingWrite : Object, key : SelectionKey) - + getInterestedOps() : int - + getJavaChannel() : DatagramChannel - + read(key : SelectionKey) : DatagramPacket - + write(data : Object, key : SelectionKey) - } - class DatagramPacket { - - data : ByteBuffer - - receiver : SocketAddress - - sender : SocketAddress - + DatagramPacket(data : ByteBuffer) - + getData() : ByteBuffer - + getReceiver() : SocketAddress - + getSender() : SocketAddress - + setReceiver(receiver : SocketAddress) - + setSender(sender : SocketAddress) - } abstract class AbstractNioChannel { - channel : SelectableChannel - channelToPendingWrites : Map> @@ -97,6 +58,32 @@ package com.iluwatar.reactor.framework { ~ setReactor(reactor : NioReactor) + write(data : Object, key : SelectionKey) } + ~class ChangeKeyOpsCommand { + - interestedOps : int + - key : SelectionKey + + ChangeKeyOpsCommand(this$0 : SelectionKey, key : int) + + run() + + toString() : String + } + interface ChannelHandler { + + handleChannelRead(AbstractNioChannel, Object, SelectionKey) {abstract} + } + class NioDatagramChannel { + - port : int + + NioDatagramChannel(port : int, handler : ChannelHandler) + + bind() + # doWrite(pendingWrite : Object, key : SelectionKey) + + getInterestedOps() : int + + getJavaChannel() : DatagramChannel + + read(key : SelectionKey) : DatagramPacket + + write(data : Object, key : SelectionKey) + } + class ThreadPoolDispatcher { + - executorService : ExecutorService + + ThreadPoolDispatcher(poolSize : int) + + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + + stop() + } class NioServerSocketChannel { - port : int + NioServerSocketChannel(port : int, handler : ChannelHandler) @@ -106,6 +93,26 @@ package com.iluwatar.reactor.framework { + getJavaChannel() : ServerSocketChannel + read(key : SelectionKey) : ByteBuffer } + class SameThreadDispatcher { + + SameThreadDispatcher() + + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + + stop() + } + interface Dispatcher { + + onChannelReadEvent(AbstractNioChannel, Object, SelectionKey) {abstract} + + stop() {abstract} + } + class DatagramPacket { + - data : ByteBuffer + - receiver : SocketAddress + - sender : SocketAddress + + DatagramPacket(data : ByteBuffer) + + getData() : ByteBuffer + + getReceiver() : SocketAddress + + getSender() : SocketAddress + + setReceiver(receiver : SocketAddress) + + setSender(sender : SocketAddress) + } class NioReactor { - dispatcher : Dispatcher - pendingCommands : Queue @@ -124,28 +131,21 @@ package com.iluwatar.reactor.framework { + start() + stop() } - ~class ChangeKeyOpsCommand { - - interestedOps : int - - key : SelectionKey - + ChangeKeyOpsCommand(this$0 : NioReactor, key : SelectionKey, interestedOps : int) - + run() - + toString() : String - } } AbstractNioChannel --> "-handler" ChannelHandler UdpLoggingClient ..+ AppClient -AbstractNioChannel --> "-reactor" NioReactor TcpLoggingClient ..+ AppClient +AbstractNioChannel --> "-reactor" NioReactor NioReactor --> "-dispatcher" Dispatcher App --> "-reactor" NioReactor App --> "-channels" AbstractNioChannel DatagramPacket ..+ NioDatagramChannel -ChangeKeyOpsCommand --+ NioReactor -App --> "-dispatcher" Dispatcher LoggingHandler --+ NioDatagramChannel -SameThreadDispatcher ..|> Dispatcher +App --> "-dispatcher" Dispatcher +ChangeKeyOpsCommand --+ NioReactor +NioDatagramChannel --|> AbstractNioChannel LoggingHandler ..|> ChannelHandler ThreadPoolDispatcher ..|> Dispatcher -NioDatagramChannel --|> AbstractNioChannel NioServerSocketChannel --|> AbstractNioChannel +SameThreadDispatcher ..|> Dispatcher @enduml \ 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 index 22b303cf5..1760cf3e4 100644 --- a/reader-writer-lock/etc/reader-writer-lock.urm.puml +++ b/reader-writer-lock/etc/reader-writer-lock.urm.puml @@ -1,21 +1,5 @@ @startuml package com.iluwatar.reader.writer.lock { - -class ReadLock { - - ReadLock(ReaderWriterLock) - + lock() - + lockInterruptibly() - + newCondition() : Condition - + tryLock() : boolean - + tryLock(time : long, unit : TimeUnit) : boolean - + unlock() - } - class Writer { - - name : String - - writeLock : Lock - + Writer(name : String, writeLock : Lock) - + run() - + write() - } class ReaderWriterLock { - currentReaderCount : int - globalMutex : Set @@ -31,7 +15,7 @@ package com.iluwatar.reader.writer.lock { + writeLock() : Lock } -class WriteLock { - - WriteLock(ReaderWriterLock) + - WriteLock() + lock() + lockInterruptibly() + newCondition() : Condition @@ -43,6 +27,22 @@ package com.iluwatar.reader.writer.lock { + App() + main(args : String[]) {static} } + -class ReadLock { + - ReadLock() + + lock() + + lockInterruptibly() + + newCondition() : Condition + + tryLock() : boolean + + tryLock(time : long, unit : TimeUnit) : boolean + + unlock() + } + class Writer { + - name : String + - writeLock : Lock + + Writer(name : String, writeLock : Lock) + + run() + + write() + } class Reader { - name : String - readLock : Lock @@ -51,8 +51,8 @@ package com.iluwatar.reader.writer.lock { + run() } } -ReadLock --+ ReaderWriterLock ReaderWriterLock --> "-readerLock" ReadLock +ReadLock --+ ReaderWriterLock ReaderWriterLock --> "-writerLock" WriteLock WriteLock --+ ReaderWriterLock @enduml \ No newline at end of file diff --git a/repository/etc/repository.urm.puml b/repository/etc/repository.urm.puml index 49a2c8fdc..ad1759033 100644 --- a/repository/etc/repository.urm.puml +++ b/repository/etc/repository.urm.puml @@ -1,9 +1,34 @@ @startuml package com.iluwatar.repository { + class PersonSpecifications { + + PersonSpecifications() + } + class NameEqualSpec { + + name : String + + NameEqualSpec(name : String) + + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate + } class App { + App() + main(args : String[]) {static} } + interface PersonRepository { + + findByName(String) : Person {abstract} + } + class AgeBetweenSpec { + - from : int + - to : int + + AgeBetweenSpec(from : int, to : int) + + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate + } + class AppConfig { + + AppConfig() + + dataSource() : DataSource + + entityManagerFactory() : LocalContainerEntityManagerFactoryBean + - jpaProperties() : Properties {static} + + main(args : String[]) {static} + + transactionManager() : JpaTransactionManager + } class Person { - age : int - id : Long @@ -23,31 +48,6 @@ package com.iluwatar.repository { + setSurname(surname : String) + toString() : String } - class AgeBetweenSpec { - - from : int - - to : int - + AgeBetweenSpec(from : int, to : int) - + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate - } - class AppConfig { - + AppConfig() - + dataSource() : DataSource - + entityManagerFactory() : LocalContainerEntityManagerFactoryBean - - jpaProperties() : Properties {static} - + main(args : String[]) {static} - + transactionManager() : JpaTransactionManager - } - interface PersonRepository { - + findByName(String) : Person {abstract} - } - class NameEqualSpec { - + name : String - + NameEqualSpec(name : String) - + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate - } - class PersonSpecifications { - + PersonSpecifications() - } } App --+ PersonSpecifications AppConfig --+ PersonSpecifications diff --git a/resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml b/resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml index 847b716a0..81560c7f5 100644 --- a/resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml +++ b/resource-acquisition-is-initialization/etc/resource-acquisition-is-initialization.urm.puml @@ -4,13 +4,13 @@ package com.iluwatar.resource.acquisition.is.initialization { + App() + main(args : String[]) {static} } - class TreasureChest { - + TreasureChest() - + close() - } class SlidingDoor { + SlidingDoor() + close() } + class TreasureChest { + + TreasureChest() + + close() + } } @enduml \ No newline at end of file diff --git a/semaphore/etc/semaphore.urm.puml b/semaphore/etc/semaphore.urm.puml index f85fff921..a94ff5a7c 100644 --- a/semaphore/etc/semaphore.urm.puml +++ b/semaphore/etc/semaphore.urm.puml @@ -1,32 +1,11 @@ @startuml package com.iluwatar.semaphore { - class FruitShop { - - available : boolean[] - - bowls : FruitBowl[] - - semaphore : Semaphore - + FruitShop() - + countFruit() : int - + returnBowl(bowl : FruitBowl) - + takeBowl() : FruitBowl - } - class FruitBowl { - - fruit : ArrayList - + FruitBowl() - + countFruit() : int - + put(f : Fruit) - + take() : Fruit - + toString() : String - } class Fruit { - type : FruitType + Fruit(type : FruitType) + getType() : FruitType + toString() : String } - interface Lock { - + acquire() {abstract} - + release() {abstract} - } class App { + App() + main(args : String[]) {static} @@ -40,6 +19,27 @@ package com.iluwatar.semaphore { + getNumLicenses() : int + release() } + class FruitShop { + - available : boolean[] + - bowls : FruitBowl[] + - semaphore : Semaphore + + FruitShop() + + countFruit() : int + + returnBowl(bowl : FruitBowl) + + takeBowl() : FruitBowl + } + interface Lock { + + acquire() {abstract} + + release() {abstract} + } + class FruitBowl { + - fruit : ArrayList + + FruitBowl() + + countFruit() : int + + put(f : Fruit) + + take() : Fruit + + toString() : String + } enum FruitType { + APPLE {static} + LEMON {static} diff --git a/servant/etc/servant.urm.puml b/servant/etc/servant.urm.puml index 48d48bd84..b7391f5dd 100644 --- a/servant/etc/servant.urm.puml +++ b/servant/etc/servant.urm.puml @@ -1,24 +1,5 @@ @startuml package com.iluwatar.servant { - class King { - - complimentReceived : boolean - - isDrunk : boolean - - isHappy : boolean - - isHungry : boolean - + King() - + changeMood() - + getDrink() - + getFed() - + getMood() : boolean - + receiveCompliments() - } - ~interface Royalty { - + changeMood() {abstract} - + getDrink() {abstract} - + getFed() {abstract} - + getMood() : boolean {abstract} - + receiveCompliments() {abstract} - } class Servant { + name : String + Servant(name : String) @@ -48,8 +29,27 @@ package com.iluwatar.servant { + main(args : String[]) {static} + scenario(servant : Servant, compliment : int) {static} } + class King { + - complimentReceived : boolean + - isDrunk : boolean + - isHappy : boolean + - isHungry : boolean + + King() + + changeMood() + + getDrink() + + getFed() + + getMood() : boolean + + receiveCompliments() + } + ~interface Royalty { + + changeMood() {abstract} + + getDrink() {abstract} + + getFed() {abstract} + + getMood() : boolean {abstract} + + receiveCompliments() {abstract} + } } App --> "-jenkins" Servant -King ..|> Royalty Queen ..|> Royalty +King ..|> Royalty @enduml \ No newline at end of file diff --git a/service-layer/etc/service-layer.urm.puml b/service-layer/etc/service-layer.urm.puml index c67ffa645..880384b9f 100644 --- a/service-layer/etc/service-layer.urm.puml +++ b/service-layer/etc/service-layer.urm.puml @@ -55,6 +55,9 @@ package com.iluwatar.servicelayer.magic { } } package com.iluwatar.servicelayer.wizard { + interface WizardDao { + + findByName(String) : Wizard {abstract} + } class Wizard { - id : Long - name : String @@ -74,9 +77,6 @@ package com.iluwatar.servicelayer.wizard { + WizardDaoImpl() + findByName(name : String) : Wizard } - interface WizardDao { - + findByName(String) : Wizard {abstract} - } } package com.iluwatar.servicelayer.app { class App { @@ -86,33 +86,14 @@ package com.iluwatar.servicelayer.app { + queryData() {static} } } -package com.iluwatar.servicelayer.spell { - class SpellDaoImpl { - + SpellDaoImpl() - + findByName(name : String) : Spell - } - class Spell { - - id : Long - - name : String - - spellbook : Spellbook - + Spell() - + Spell(name : String) - + getId() : Long - + getName() : String - + getSpellbook() : Spellbook - + setId(id : Long) - + setName(name : String) - + setSpellbook(spellbook : Spellbook) - + toString() : String - } - interface SpellDao { - + findByName(String) : Spell {abstract} - } -} package com.iluwatar.servicelayer.spellbook { interface SpellbookDao { + findByName(String) : Spellbook {abstract} } + class SpellbookDaoImpl { + + SpellbookDaoImpl() + + findByName(name : String) : Spellbook + } class Spellbook { - id : Long - name : String @@ -131,9 +112,28 @@ package com.iluwatar.servicelayer.spellbook { + setWizards(wizards : Set) + toString() : String } - class SpellbookDaoImpl { - + SpellbookDaoImpl() - + findByName(name : String) : Spellbook +} +package com.iluwatar.servicelayer.spell { + class SpellDaoImpl { + + SpellDaoImpl() + + findByName(name : String) : Spell + } + interface SpellDao { + + findByName(String) : Spell {abstract} + } + class Spell { + - id : Long + - name : String + - spellbook : Spellbook + + Spell() + + Spell(name : String) + + getId() : Long + + getName() : String + + getSpellbook() : Spellbook + + setId(id : Long) + + setName(name : String) + + setSpellbook(spellbook : Spellbook) + + toString() : String } } MagicServiceImpl --> "-wizardDao" WizardDao @@ -141,18 +141,18 @@ MagicServiceImpl --> "-spellbookDao" SpellbookDao MagicServiceImpl --> "-spellDao" SpellDao Spellbook --> "-spells" Spell Spellbook --> "-wizards" Wizard -Wizard --|> BaseEntity -SpellbookDao --|> Dao SpellDaoImpl ..|> SpellDao SpellDaoImpl --|> DaoBaseImpl -MagicServiceImpl ..|> MagicService -DaoBaseImpl ..|> Dao -WizardDaoImpl ..|> WizardDao -WizardDaoImpl --|> DaoBaseImpl -Spellbook --|> BaseEntity +SpellbookDao --|> Dao +WizardDao --|> Dao SpellbookDaoImpl ..|> SpellbookDao SpellbookDaoImpl --|> DaoBaseImpl -Spell --|> BaseEntity -WizardDao --|> Dao +MagicServiceImpl ..|> MagicService SpellDao --|> Dao +Spell --|> BaseEntity +Spellbook --|> BaseEntity +Wizard --|> BaseEntity +WizardDaoImpl ..|> WizardDao +WizardDaoImpl --|> DaoBaseImpl +DaoBaseImpl ..|> Dao @enduml \ No newline at end of file diff --git a/service-locator/etc/service-locator.urm.puml b/service-locator/etc/service-locator.urm.puml index 085b05b28..9e41e7f40 100644 --- a/service-locator/etc/service-locator.urm.puml +++ b/service-locator/etc/service-locator.urm.puml @@ -1,25 +1,10 @@ @startuml package com.iluwatar.servicelocator { - interface Service { - + execute() {abstract} - + getId() : int {abstract} - + getName() : String {abstract} - } - class InitContext { - + InitContext() - + lookup(serviceName : String) : Object - } class ServiceLocator { - serviceCache : ServiceCache {static} - ServiceLocator() + getService(serviceJndiName : String) : Service {static} } - class ServiceCache { - - serviceCache : Map - + ServiceCache() - + addService(newService : Service) - + getService(serviceName : String) : Service - } class App { + App() + main(args : String[]) {static} @@ -32,6 +17,21 @@ package com.iluwatar.servicelocator { + getId() : int + getName() : String } + class InitContext { + + InitContext() + + lookup(serviceName : String) : Object + } + class ServiceCache { + - serviceCache : Map + + ServiceCache() + + addService(newService : Service) + + getService(serviceName : String) : Service + } + interface Service { + + execute() {abstract} + + getId() : int {abstract} + + getName() : String {abstract} + } } ServiceLocator --> "-serviceCache" ServiceCache ServiceImpl ..|> Service diff --git a/singleton/etc/singleton.urm.puml b/singleton/etc/singleton.urm.puml index f5ec19879..a13091772 100644 --- a/singleton/etc/singleton.urm.puml +++ b/singleton/etc/singleton.urm.puml @@ -1,32 +1,32 @@ @startuml package com.iluwatar.singleton { + class App { + + App() + + main(args : String[]) {static} + } class ThreadSafeLazyLoadedIvoryTower { - instance : ThreadSafeLazyLoadedIvoryTower {static} - ThreadSafeLazyLoadedIvoryTower() + getInstance() : ThreadSafeLazyLoadedIvoryTower {static} } - -class HelperHolder { - + INSTANCE : InitializingOnDemandHolderIdiom {static} - - HelperHolder() - } - class App { - + App() - + main(args : String[]) {static} + class InitializingOnDemandHolderIdiom { + - InitializingOnDemandHolderIdiom() + + getInstance() : InitializingOnDemandHolderIdiom {static} } class ThreadSafeDoubleCheckLocking { - instance : ThreadSafeDoubleCheckLocking {static} - ThreadSafeDoubleCheckLocking() + getInstance() : ThreadSafeDoubleCheckLocking {static} } - class InitializingOnDemandHolderIdiom { - - InitializingOnDemandHolderIdiom() - + getInstance() : InitializingOnDemandHolderIdiom {static} - } class IvoryTower { - INSTANCE : IvoryTower {static} - IvoryTower() + getInstance() : IvoryTower {static} } + -class HelperHolder { + - INSTANCE : InitializingOnDemandHolderIdiom {static} + - HelperHolder() + } enum EnumIvoryTower { + INSTANCE {static} + toString() : String diff --git a/specification/etc/specification.urm.puml b/specification/etc/specification.urm.puml index 0009a1bcd..2f194d340 100644 --- a/specification/etc/specification.urm.puml +++ b/specification/etc/specification.urm.puml @@ -1,17 +1,5 @@ @startuml package com.iluwatar.specification.creature { - class Goblin { - + Goblin() - } - interface Creature { - + getColor() : Color {abstract} - + getMovement() : Movement {abstract} - + getName() : String {abstract} - + getSize() : Size {abstract} - } - class Troll { - + Troll() - } abstract class AbstractCreature { - color : Color - movement : Movement @@ -24,20 +12,41 @@ package com.iluwatar.specification.creature { + getSize() : Size + toString() : String } + class Troll { + + Troll() + } + class Octopus { + + Octopus() + } class Shark { + Shark() } + class Goblin { + + Goblin() + } class KillerBee { + KillerBee() } - class Octopus { - + Octopus() + interface Creature { + + getColor() : Color {abstract} + + getMovement() : Movement {abstract} + + getName() : String {abstract} + + getSize() : Size {abstract} } class Dragon { + Dragon() } } package com.iluwatar.specification.property { + enum Size { + + LARGE {static} + + NORMAL {static} + + SMALL {static} + - title : String + + toString() : String + + valueOf(name : String) : Size {static} + + values() : Size[] {static} + } enum Color { + DARK {static} + GREEN {static} @@ -57,15 +66,6 @@ package com.iluwatar.specification.property { + valueOf(name : String) : Movement {static} + values() : Movement[] {static} } - enum Size { - + LARGE {static} - + NORMAL {static} - + SMALL {static} - - title : String - + toString() : String - + valueOf(name : String) : Size {static} - + values() : Size[] {static} - } } package com.iluwatar.specification.app { class App { @@ -74,9 +74,9 @@ package com.iluwatar.specification.app { } } package com.iluwatar.specification.selector { - class SizeSelector { - - s : Size - + SizeSelector(s : Size) + class MovementSelector { + - m : Movement + + MovementSelector(m : Movement) + test(t : Creature) : boolean } class ColorSelector { @@ -84,9 +84,9 @@ package com.iluwatar.specification.selector { + ColorSelector(c : Color) + test(t : Creature) : boolean } - class MovementSelector { - - m : Movement - + MovementSelector(m : Movement) + class SizeSelector { + - s : Size + + SizeSelector(s : Size) + test(t : Creature) : boolean } } @@ -96,11 +96,11 @@ MovementSelector --> "-m" Movement AbstractCreature --> "-movement" Movement AbstractCreature --> "-size" Size ColorSelector --> "-c" Color -Goblin --|> AbstractCreature -Troll --|> AbstractCreature AbstractCreature ..|> Creature -Shark --|> AbstractCreature -KillerBee --|> AbstractCreature +Troll --|> AbstractCreature Octopus --|> AbstractCreature +Shark --|> AbstractCreature +Goblin --|> AbstractCreature +KillerBee --|> AbstractCreature Dragon --|> AbstractCreature @enduml \ No newline at end of file diff --git a/state/etc/state.urm.puml b/state/etc/state.urm.puml index a0951ff6e..378c11cd1 100644 --- a/state/etc/state.urm.puml +++ b/state/etc/state.urm.puml @@ -1,5 +1,19 @@ @startuml package com.iluwatar.state { + class PeacefulState { + - mammoth : Mammoth + + PeacefulState(mammoth : Mammoth) + + observe() + + onEnterState() + } + interface State { + + observe() {abstract} + + onEnterState() {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } class AngryState { - mammoth : Mammoth + AngryState(mammoth : Mammoth) @@ -14,24 +28,10 @@ package com.iluwatar.state { + timePasses() + toString() : String } - interface State { - + observe() {abstract} - + onEnterState() {abstract} - } - class PeacefulState { - - mammoth : Mammoth - + PeacefulState(mammoth : Mammoth) - + observe() - + onEnterState() - } - class App { - + App() - + main(args : String[]) {static} - } } -PeacefulState --> "-mammoth" Mammoth AngryState --> "-mammoth" Mammoth +PeacefulState --> "-mammoth" Mammoth Mammoth --> "-state" State -AngryState ..|> State PeacefulState ..|> State +AngryState ..|> State @enduml \ No newline at end of file diff --git a/step-builder/etc/step-builder.urm.puml b/step-builder/etc/step-builder.urm.puml index cc1f88ef0..129ecbf30 100644 --- a/step-builder/etc/step-builder.urm.puml +++ b/step-builder/etc/step-builder.urm.puml @@ -1,8 +1,16 @@ @startuml package com.iluwatar.stepbuilder { + interface AbilityStep { + + noAbilities() : BuildStep {abstract} + + noMoreAbilities() : BuildStep {abstract} + + withAbility(String) : AbilityStep {abstract} + } interface BuildStep { + build() : Character {abstract} } + interface NameStep { + + name(String) : ClassStep {abstract} + } -class CharacterSteps { - abilities : List - fighterClass : String @@ -27,22 +35,6 @@ package com.iluwatar.stepbuilder { + App() + main(args : String[]) {static} } - interface ClassStep { - + fighterClass(String) : WeaponStep {abstract} - + wizardClass(String) : SpellStep {abstract} - } - interface WeaponStep { - + noWeapon() : BuildStep {abstract} - + withWeapon(String) : AbilityStep {abstract} - } - interface AbilityStep { - + noAbilities() : BuildStep {abstract} - + noMoreAbilities() : BuildStep {abstract} - + withAbility(String) : AbilityStep {abstract} - } - interface NameStep { - + name(String) : ClassStep {abstract} - } class CharacterStepBuilder { - CharacterStepBuilder() + newBuilder() : NameStep {static} @@ -73,13 +65,21 @@ package com.iluwatar.stepbuilder { + noSpell() : BuildStep {abstract} + withSpell(String) : AbilityStep {abstract} } + interface ClassStep { + + fighterClass(String) : WeaponStep {abstract} + + wizardClass(String) : SpellStep {abstract} + } + interface WeaponStep { + + noWeapon() : BuildStep {abstract} + + withWeapon(String) : AbilityStep {abstract} + } } App --+ CharacterStepBuilder WeaponStep ..+ CharacterStepBuilder -SpellStep ..+ CharacterStepBuilder -AbilityStep ..+ CharacterStepBuilder ClassStep ..+ CharacterStepBuilder +SpellStep ..+ CharacterStepBuilder CharacterSteps ..+ CharacterStepBuilder +AbilityStep ..+ CharacterStepBuilder NameStep ..+ CharacterStepBuilder BuildStep ..+ CharacterStepBuilder CharacterSteps ..|> NameStep diff --git a/strategy/etc/strategy.urm.puml b/strategy/etc/strategy.urm.puml index 2cc072863..db86b9ed6 100644 --- a/strategy/etc/strategy.urm.puml +++ b/strategy/etc/strategy.urm.puml @@ -6,28 +6,28 @@ package com.iluwatar.strategy { + changeStrategy(strategy : DragonSlayingStrategy) + goToBattle() } - class SpellStrategy { - + SpellStrategy() + interface DragonSlayingStrategy { + + execute() {abstract} + } + class App { + + App() + + main(args : String[]) {static} + } + class MeleeStrategy { + + MeleeStrategy() + execute() } class ProjectileStrategy { + ProjectileStrategy() + execute() } - interface DragonSlayingStrategy { - + execute() {abstract} - } - class MeleeStrategy { - + MeleeStrategy() + class SpellStrategy { + + SpellStrategy() + execute() } - class App { - + App() - + main(args : String[]) {static} - } } DragonSlayer --> "-strategy" DragonSlayingStrategy -SpellStrategy ..|> DragonSlayingStrategy -ProjectileStrategy ..|> DragonSlayingStrategy MeleeStrategy ..|> DragonSlayingStrategy +ProjectileStrategy ..|> DragonSlayingStrategy +SpellStrategy ..|> DragonSlayingStrategy @enduml \ No newline at end of file diff --git a/template-method/etc/template-method.urm.puml b/template-method/etc/template-method.urm.puml index c98287bc6..c2c6045fe 100644 --- a/template-method/etc/template-method.urm.puml +++ b/template-method/etc/template-method.urm.puml @@ -1,17 +1,17 @@ @startuml package com.iluwatar.templatemethod { - class SubtleMethod { - + SubtleMethod() - # confuseTarget(target : String) - # pickTarget() : String - # stealTheItem(target : String) - } class HitAndRunMethod { + HitAndRunMethod() # confuseTarget(target : String) # pickTarget() : String # stealTheItem(target : String) } + class HalflingThief { + - method : StealingMethod + + HalflingThief(method : StealingMethod) + + changeMethod(method : StealingMethod) + + steal() + } abstract class StealingMethod { + StealingMethod() # confuseTarget(String) {abstract} @@ -19,18 +19,18 @@ package com.iluwatar.templatemethod { + steal() # stealTheItem(String) {abstract} } + class SubtleMethod { + + SubtleMethod() + # confuseTarget(target : String) + # pickTarget() : String + # stealTheItem(target : String) + } class App { + App() + main(args : String[]) {static} } - class HalflingThief { - - method : StealingMethod - + HalflingThief(method : StealingMethod) - + changeMethod(method : StealingMethod) - + steal() - } } HalflingThief --> "-method" StealingMethod -SubtleMethod --|> StealingMethod HitAndRunMethod --|> StealingMethod +SubtleMethod --|> StealingMethod @enduml \ No newline at end of file diff --git a/thread-pool/etc/thread-pool.urm.puml b/thread-pool/etc/thread-pool.urm.puml index 2b73e2d53..421ea1dce 100644 --- a/thread-pool/etc/thread-pool.urm.puml +++ b/thread-pool/etc/thread-pool.urm.puml @@ -1,14 +1,5 @@ @startuml package com.iluwatar.threadpool { - class Worker { - - task : Task - + Worker(task : Task) - + run() - } - class App { - + App() - + main(args : String[]) {static} - } abstract class Task { - ID_GENERATOR : AtomicInteger {static} - id : int @@ -18,18 +9,27 @@ package com.iluwatar.threadpool { + getTimeMs() : int + toString() : String } - class PotatoPeelingTask { - - TIME_PER_POTATO : int {static} - + PotatoPeelingTask(numPotatoes : int) - + toString() : String - } class CoffeeMakingTask { - TIME_PER_CUP : int {static} + CoffeeMakingTask(numCups : int) + toString() : String } + class Worker { + - task : Task + + Worker(task : Task) + + run() + } + class PotatoPeelingTask { + - TIME_PER_POTATO : int {static} + + PotatoPeelingTask(numPotatoes : int) + + toString() : String + } + class App { + + App() + + main(args : String[]) {static} + } } Worker --> "-task" Task -PotatoPeelingTask --|> Task CoffeeMakingTask --|> Task +PotatoPeelingTask --|> Task @enduml \ No newline at end of file diff --git a/tolerant-reader/etc/tolerant-reader.urm.puml b/tolerant-reader/etc/tolerant-reader.urm.puml index 9e2bc83b3..f203f8257 100644 --- a/tolerant-reader/etc/tolerant-reader.urm.puml +++ b/tolerant-reader/etc/tolerant-reader.urm.puml @@ -1,11 +1,5 @@ @startuml package com.iluwatar.tolerantreader { - class RainbowFishSerializer { - - RainbowFishSerializer() - + readV1(filename : String) : RainbowFish {static} - + writeV1(rainbowFish : RainbowFish, filename : String) {static} - + writeV2(rainbowFish : RainbowFishV2, filename : String) {static} - } class RainbowFish { - age : int - lengthMeters : int @@ -18,6 +12,10 @@ package com.iluwatar.tolerantreader { + getName() : String + getWeightTons() : int } + class App { + + App() + + main(args : String[]) {static} + } class RainbowFishV2 { - angry : boolean - hungry : boolean @@ -29,9 +27,11 @@ package com.iluwatar.tolerantreader { + getHungry() : boolean + getSleeping() : boolean } - class App { - + App() - + main(args : String[]) {static} + class RainbowFishSerializer { + - RainbowFishSerializer() + + readV1(filename : String) : RainbowFish {static} + + writeV1(rainbowFish : RainbowFish, filename : String) {static} + + writeV2(rainbowFish : RainbowFishV2, filename : String) {static} } } RainbowFishV2 --|> RainbowFish diff --git a/twin/etc/twin.urm.puml b/twin/etc/twin.urm.puml index b95325abb..b4bd52468 100644 --- a/twin/etc/twin.urm.puml +++ b/twin/etc/twin.urm.puml @@ -1,9 +1,10 @@ @startuml package com.iluwatar.twin { - class App { - + App() - + main(args : String[]) {static} - - waiting() {static} + abstract class GameItem { + + GameItem() + + click() {abstract} + + doDraw() {abstract} + + draw() } class BallItem { - isSuspended : boolean @@ -14,11 +15,10 @@ package com.iluwatar.twin { + move() + setTwin(twin : BallThread) } - abstract class GameItem { - + GameItem() - + click() {abstract} - + doDraw() {abstract} - + draw() + class App { + + App() + + main(args : String[]) {static} + - waiting() {static} } } BallItem --|> GameItem diff --git a/value-object/etc/value-object.urm.puml b/value-object/etc/value-object.urm.puml index 223f91957..6c81de017 100644 --- a/value-object/etc/value-object.urm.puml +++ b/value-object/etc/value-object.urm.puml @@ -1,9 +1,5 @@ @startuml package com.iluwatar.value.object { - class App { - + App() - + main(args : String[]) {static} - } class HeroStat { - intelligence : int - luck : int @@ -17,5 +13,9 @@ package com.iluwatar.value.object { + toString() : String + valueOf(strength : int, intelligence : int, luck : int) : HeroStat {static} } + class App { + + App() + + main(args : String[]) {static} + } } @enduml \ No newline at end of file diff --git a/visitor/etc/visitor.urm.puml b/visitor/etc/visitor.urm.puml index 3f5689f71..1f28e4e2f 100644 --- a/visitor/etc/visitor.urm.puml +++ b/visitor/etc/visitor.urm.puml @@ -1,57 +1,57 @@ @startuml package com.iluwatar.visitor { + class Commander { + + Commander(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + interface UnitVisitor { + + visitCommander(Commander) {abstract} + + visitSergeant(Sergeant) {abstract} + + visitSoldier(Soldier) {abstract} + } class CommanderVisitor { + CommanderVisitor() + visitCommander(commander : Commander) + visitSergeant(sergeant : Sergeant) + visitSoldier(soldier : Soldier) } + class Soldier { + + Soldier(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + class App { + + App() + + main(args : String[]) {static} + } + abstract class Unit { + - children : Unit[] + + Unit(children : Unit[]) + + accept(visitor : UnitVisitor) + } + class SoldierVisitor { + + SoldierVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } + class SergeantVisitor { + + SergeantVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } class Sergeant { + Sergeant(children : Unit[]) + accept(visitor : UnitVisitor) + toString() : String } - class Commander { - + Commander(children : Unit[]) - + accept(visitor : UnitVisitor) - + toString() : String - } - abstract class Unit { - - children : Unit[] - + Unit(children : Unit[]) - + accept(visitor : UnitVisitor) - } - class Soldier { - + Soldier(children : Unit[]) - + accept(visitor : UnitVisitor) - + toString() : String - } - class SergeantVisitor { - + SergeantVisitor() - + visitCommander(commander : Commander) - + visitSergeant(sergeant : Sergeant) - + visitSoldier(soldier : Soldier) - } - interface UnitVisitor { - + visitCommander(Commander) {abstract} - + visitSergeant(Sergeant) {abstract} - + visitSoldier(Soldier) {abstract} - } - class App { - + App() - + main(args : String[]) {static} - } - class SoldierVisitor { - + SoldierVisitor() - + visitCommander(commander : Commander) - + visitSergeant(sergeant : Sergeant) - + visitSoldier(soldier : Soldier) - } } -CommanderVisitor ..|> UnitVisitor -Sergeant --|> Unit Commander --|> Unit +CommanderVisitor ..|> UnitVisitor Soldier --|> Unit -SergeantVisitor ..|> UnitVisitor SoldierVisitor ..|> UnitVisitor +SergeantVisitor ..|> UnitVisitor +Sergeant --|> Unit @enduml \ No newline at end of file From dbd605e3786eb0d90ded55436976784865328d53 Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 19 Sep 2016 21:50:04 +0100 Subject: [PATCH 067/492] Changes based on latest code review --- .../com/iluwatar/event/asynchronous/App.java | 29 +++++++++++-------- .../iluwatar/event/asynchronous/Event.java | 17 ++++++++++- .../event/asynchronous/EventManager.java | 13 ++++++--- .../src/main/java/config.properties | 2 +- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java index f951af07c..65ae02e56 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java @@ -138,11 +138,10 @@ public class App { Scanner s = new Scanner(System.in); int option = -1; - while (option != 5) { + while (option != 4) { System.out.println("Hello. Would you like to boil some eggs?"); - System.out.println( - "(1) BOIL AN EGG \n(2) STOP BOILING THIS EGG \n(3) HOW IS MY EGG? \n(4) HOW ARE MY EGGS? \n(5) EXIT"); - System.out.print("Choose [1,2,3,4,5]: "); + System.out.println("(1) BOIL AN EGG \n(2) STOP BOILING THIS EGG \n(3) HOW ARE MY EGGS? \n(4) EXIT"); + System.out.print("Choose [1,2,3,4]: "); option = s.nextInt(); if (option == 1) { @@ -181,16 +180,22 @@ public class App { System.out.println(e.getMessage()); } } else if (option == 3) { - System.out.print("Which egg?: "); - int eventId = s.nextInt(); - try { - eventManager.status(eventId); - } catch (EventDoesNotExistException e) { - System.out.println(e.getMessage()); + s.nextLine(); + System.out.print("Just one egg (O) OR all of them (A) ?: "); + String eggChoice = s.nextLine(); + + if (eggChoice.equalsIgnoreCase("O")) { + System.out.print("Which egg?: "); + int eventId = s.nextInt(); + try { + eventManager.status(eventId); + } catch (EventDoesNotExistException e) { + System.out.println(e.getMessage()); + } + } else if (eggChoice.equalsIgnoreCase("A")) { + eventManager.statusOfAllEvents(); } } else if (option == 4) { - eventManager.statusOfAllEvents(); - } else if (option == 5) { eventManager.shutdown(); } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java index 1cb04acdc..c2e14ad68 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java @@ -25,13 +25,25 @@ public class Event implements IEvent, Runnable { private int eventId; private int eventTime; + private boolean isSynchronous; private Thread thread; private boolean isComplete = false; private ThreadCompleteListener eventListener; - public Event(final int eventId, final int eventTime) { + /** + * + * @param eventId event ID + * @param eventTime event time + * @param isSynchronous is of synchronous type + */ + public Event(final int eventId, final int eventTime, final boolean isSynchronous) { this.eventId = eventId; this.eventTime = eventTime; + this.isSynchronous = isSynchronous; + } + + public boolean isSynchronous() { + return isSynchronous; } @Override @@ -42,6 +54,9 @@ public class Event implements IEvent, Runnable { @Override public void stop() { + if (null == thread) { + return; + } thread.interrupt(); } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java index e65816cec..dae995e38 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java @@ -61,11 +61,12 @@ public class EventManager implements ThreadCompleteListener { */ public int create(int eventTime) throws MaxNumOfEventsAllowedException, InvalidOperationException, LongRunningEventException { - int eventId = createEvent(eventTime); if (currentlyRunningSyncEvent != -1) { throw new InvalidOperationException( "Event [" + currentlyRunningSyncEvent + "] is still running. Please wait until it finishes and try again."); } + + int eventId = createEvent(eventTime, true); currentlyRunningSyncEvent = eventId; return eventId; @@ -80,10 +81,11 @@ public class EventManager implements ThreadCompleteListener { * @throws LongRunningEventException Long running events are not allowed in the app. */ public int createAsync(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { - return createEvent(eventTime); + return createEvent(eventTime, false); } - private int createEvent(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { + private int createEvent(int eventTime, boolean isSynchronous) + throws MaxNumOfEventsAllowedException, LongRunningEventException { if (eventPool.size() == MAX_RUNNING_EVENTS) { throw new MaxNumOfEventsAllowedException("Too many events are running at the moment. Please try again later."); } @@ -95,7 +97,7 @@ public class EventManager implements ThreadCompleteListener { int newEventId = generateId(); - Event newEvent = new Event(newEventId, eventTime); + Event newEvent = new Event(newEventId, eventTime, isSynchronous); newEvent.addListener(this); eventPool.put(newEventId, newEvent); @@ -194,6 +196,9 @@ public class EventManager implements ThreadCompleteListener { @Override public void completedEventHandler(int eventId) { eventPool.get(eventId).status(); + if (eventPool.get(eventId).isSynchronous()) { + currentlyRunningSyncEvent = -1; + } eventPool.remove(eventId); } diff --git a/event-asynchronous/src/main/java/config.properties b/event-asynchronous/src/main/java/config.properties index edbe90e05..7216f665d 100644 --- a/event-asynchronous/src/main/java/config.properties +++ b/event-asynchronous/src/main/java/config.properties @@ -1 +1 @@ -INTERACTIVE_MODE=NO \ No newline at end of file +INTERACTIVE_MODE=YES \ No newline at end of file From 371b262a5135484d83efb0666269af0a55c6f185 Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 19 Sep 2016 21:50:23 +0100 Subject: [PATCH 068/492] Changes based on latest code review --- event-asynchronous/src/main/java/config.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event-asynchronous/src/main/java/config.properties b/event-asynchronous/src/main/java/config.properties index 7216f665d..edbe90e05 100644 --- a/event-asynchronous/src/main/java/config.properties +++ b/event-asynchronous/src/main/java/config.properties @@ -1 +1 @@ -INTERACTIVE_MODE=YES \ No newline at end of file +INTERACTIVE_MODE=NO \ No newline at end of file From 6ed842e58bab97bc7eebe47575838a0b1f0910d7 Mon Sep 17 00:00:00 2001 From: Christoffer Hamberg Date: Thu, 22 Sep 2016 09:35:17 +0200 Subject: [PATCH 069/492] Caching pattern: Refactor shutdown hook to use method reference --- caching/src/main/java/com/iluwatar/caching/AppManager.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/caching/src/main/java/com/iluwatar/caching/AppManager.java b/caching/src/main/java/com/iluwatar/caching/AppManager.java index 2967c759f..13ef4d4dd 100644 --- a/caching/src/main/java/com/iluwatar/caching/AppManager.java +++ b/caching/src/main/java/com/iluwatar/caching/AppManager.java @@ -64,12 +64,7 @@ public final class AppManager { public static void initCachingPolicy(CachingPolicy policy) { cachingPolicy = policy; if (cachingPolicy == CachingPolicy.BEHIND) { - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - CacheStore.flushCache(); - } - })); + Runtime.getRuntime().addShutdownHook(new Thread(CacheStore::flushCache)); } CacheStore.clearCache(); } From 865f788612b4c5fd7fd978e346c47174750f8af4 Mon Sep 17 00:00:00 2001 From: Christoffer Hamberg Date: Thu, 22 Sep 2016 09:38:23 +0200 Subject: [PATCH 070/492] Caching pattern: Refactor LRU cache to avoid NPE and unnecessary cache lookup --- caching/src/main/java/com/iluwatar/caching/LruCache.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/caching/src/main/java/com/iluwatar/caching/LruCache.java b/caching/src/main/java/com/iluwatar/caching/LruCache.java index 5c5549afd..4527b5548 100644 --- a/caching/src/main/java/com/iluwatar/caching/LruCache.java +++ b/caching/src/main/java/com/iluwatar/caching/LruCache.java @@ -136,10 +136,11 @@ public class LruCache { * Invalidate cache for user */ public void invalidate(String userId) { - System.out.println("# " + userId + " has been updated! Removing older version from cache..."); - Node toBeRemoved = cache.get(userId); - remove(toBeRemoved); - cache.remove(userId); + Node toBeRemoved = cache.remove(userId); + if (toBeRemoved != null) { + System.out.println("# " + userId + " has been updated! Removing older version from cache..."); + remove(toBeRemoved); + } } public boolean isFull() { From e3355d76d1930f935d902f54d4cf7fae4f94bd24 Mon Sep 17 00:00:00 2001 From: Christoffer Hamberg Date: Thu, 22 Sep 2016 20:33:24 +0200 Subject: [PATCH 071/492] Caching pattern: Style fix for null check --- .../src/main/java/com/iluwatar/caching/CacheStore.java | 4 ++-- caching/src/main/java/com/iluwatar/caching/DbManager.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/caching/src/main/java/com/iluwatar/caching/CacheStore.java b/caching/src/main/java/com/iluwatar/caching/CacheStore.java index 5903f8219..dd425645e 100644 --- a/caching/src/main/java/com/iluwatar/caching/CacheStore.java +++ b/caching/src/main/java/com/iluwatar/caching/CacheStore.java @@ -40,7 +40,7 @@ public class CacheStore { * Init cache capacity */ public static void initCapacity(int capacity) { - if (null == cache) { + if (cache == null) { cache = new LruCache(capacity); } else { cache.setCapacity(capacity); @@ -121,7 +121,7 @@ public class CacheStore { * Clears cache */ public static void clearCache() { - if (null != cache) { + if (cache != null) { cache.clear(); } } diff --git a/caching/src/main/java/com/iluwatar/caching/DbManager.java b/caching/src/main/java/com/iluwatar/caching/DbManager.java index c12461d0c..455302106 100644 --- a/caching/src/main/java/com/iluwatar/caching/DbManager.java +++ b/caching/src/main/java/com/iluwatar/caching/DbManager.java @@ -82,7 +82,7 @@ public final class DbManager { } return null; } - if (null == db) { + if (db == null) { try { connect(); } catch (ParseException e) { @@ -106,7 +106,7 @@ public final class DbManager { virtualDB.put(userAccount.getUserId(), userAccount); return; } - if (null == db) { + if (db == null) { try { connect(); } catch (ParseException e) { @@ -126,7 +126,7 @@ public final class DbManager { virtualDB.put(userAccount.getUserId(), userAccount); return; } - if (null == db) { + if (db == null) { try { connect(); } catch (ParseException e) { @@ -148,7 +148,7 @@ public final class DbManager { virtualDB.put(userAccount.getUserId(), userAccount); return; } - if (null == db) { + if (db == null) { try { connect(); } catch (ParseException e) { From b31edda3cf9b376423e1a6cec0b7803a9597e522 Mon Sep 17 00:00:00 2001 From: Christoffer Hamberg Date: Thu, 22 Sep 2016 20:41:26 +0200 Subject: [PATCH 072/492] Caching pattern: Implementation of Cache-Aside pattern --- .../main/java/com/iluwatar/caching/App.java | 23 +++++++++++++++ .../java/com/iluwatar/caching/AppManager.java | 29 +++++++++++++++++++ .../java/com/iluwatar/caching/CacheStore.java | 21 ++++++++++++++ .../com/iluwatar/caching/CachingPolicy.java | 2 +- .../com/iluwatar/caching/CachingTest.java | 5 ++++ 5 files changed, 79 insertions(+), 1 deletion(-) diff --git a/caching/src/main/java/com/iluwatar/caching/App.java b/caching/src/main/java/com/iluwatar/caching/App.java index 8e5a84085..4a3a9ab42 100644 --- a/caching/src/main/java/com/iluwatar/caching/App.java +++ b/caching/src/main/java/com/iluwatar/caching/App.java @@ -74,6 +74,7 @@ public class App { app.useReadAndWriteThroughStrategy(); app.useReadThroughAndWriteAroundStrategy(); app.useReadThroughAndWriteBehindStrategy(); + app.useCacheAsideStategy(); } /** @@ -136,4 +137,26 @@ public class App { AppManager.find("004"); System.out.println(AppManager.printCacheContent()); } + + /** + * Cache-Aside + */ + public void useCacheAsideStategy() { + System.out.println("# CachingPolicy.ASIDE"); + AppManager.initCachingPolicy(CachingPolicy.ASIDE); + System.out.println(AppManager.printCacheContent()); + + UserAccount userAccount3 = new UserAccount("003", "Adam", "He likes food."); + UserAccount userAccount4 = new UserAccount("004", "Rita", "She hates cats."); + UserAccount userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard."); + AppManager.save(userAccount3); + AppManager.save(userAccount4); + AppManager.save(userAccount5); + + System.out.println(AppManager.printCacheContent()); + AppManager.find("003"); + System.out.println(AppManager.printCacheContent()); + AppManager.find("004"); + System.out.println(AppManager.printCacheContent()); + } } diff --git a/caching/src/main/java/com/iluwatar/caching/AppManager.java b/caching/src/main/java/com/iluwatar/caching/AppManager.java index 13ef4d4dd..2d6a424a3 100644 --- a/caching/src/main/java/com/iluwatar/caching/AppManager.java +++ b/caching/src/main/java/com/iluwatar/caching/AppManager.java @@ -81,6 +81,8 @@ public final class AppManager { return CacheStore.readThrough(userId); } else if (cachingPolicy == CachingPolicy.BEHIND) { return CacheStore.readThroughWithWriteBackPolicy(userId); + } else if (cachingPolicy == CachingPolicy.ASIDE) { + return findAside(userId); } return null; } @@ -95,10 +97,37 @@ public final class AppManager { CacheStore.writeAround(userAccount); } else if (cachingPolicy == CachingPolicy.BEHIND) { CacheStore.writeBehind(userAccount); + } else if (cachingPolicy == CachingPolicy.ASIDE) { + saveAside(userAccount); } } public static String printCacheContent() { return CacheStore.print(); } + + /** + * Cache-Aside save user account helper + */ + private static void saveAside(UserAccount userAccount) { + DbManager.updateDb(userAccount); + CacheStore.invalidate(userAccount.getUserId()); + } + + /** + * Cache-Aside find user account helper + */ + private static UserAccount findAside(String userId) { + UserAccount userAccount = CacheStore.get(userId); + if (userAccount != null) { + return userAccount; + } + + userAccount = DbManager.readFromDb(userId); + if (userAccount != null) { + CacheStore.set(userId, userAccount); + } + + return userAccount; + } } diff --git a/caching/src/main/java/com/iluwatar/caching/CacheStore.java b/caching/src/main/java/com/iluwatar/caching/CacheStore.java index dd425645e..c2b95a1bd 100644 --- a/caching/src/main/java/com/iluwatar/caching/CacheStore.java +++ b/caching/src/main/java/com/iluwatar/caching/CacheStore.java @@ -153,4 +153,25 @@ public class CacheStore { sb.append("----\n"); return sb.toString(); } + + /** + * Delegate to backing cache store + */ + public static UserAccount get(String userId) { + return cache.get(userId); + } + + /** + * Delegate to backing cache store + */ + public static void set(String userId, UserAccount userAccount) { + cache.set(userId, userAccount); + } + + /** + * Delegate to backing cache store + */ + public static void invalidate(String userId) { + cache.invalidate(userId); + } } diff --git a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java index 490113baa..0c907fe88 100644 --- a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java +++ b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java @@ -28,7 +28,7 @@ package com.iluwatar.caching; * */ public enum CachingPolicy { - THROUGH("through"), AROUND("around"), BEHIND("behind"); + THROUGH("through"), AROUND("around"), BEHIND("behind"), ASIDE("aside"); private String policy; diff --git a/caching/src/test/java/com/iluwatar/caching/CachingTest.java b/caching/src/test/java/com/iluwatar/caching/CachingTest.java index 19262a3b6..9d2299902 100644 --- a/caching/src/test/java/com/iluwatar/caching/CachingTest.java +++ b/caching/src/test/java/com/iluwatar/caching/CachingTest.java @@ -60,4 +60,9 @@ public class CachingTest { public void testReadThroughAndWriteBehindStrategy() { app.useReadThroughAndWriteBehindStrategy(); } + + @Test + public void testCacheAsideStrategy() { + app.useCacheAsideStategy(); + } } From c5e6dcc11b59db979751c07316fda6daccb9730d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 30 Sep 2016 19:38:28 +0300 Subject: [PATCH 073/492] Reached milestone 1.13.0 --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- command/pom.xml | 2 +- composite/pom.xml | 2 +- dao/pom.xml | 2 +- data-mapper/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- execute-around/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- message-channel/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- publish-subscribe/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- singleton/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strategy/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- twin/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 92 files changed, 95 insertions(+), 95 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index b7a348d26..be9aa68b9 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index ec0f700a5..1d54f0c86 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 abstract-factory diff --git a/adapter/pom.xml b/adapter/pom.xml index 2c99796f4..d8414f85d 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 169d0da94..46d7d72c7 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index 986540344..5d2d97fe6 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index f8844dd39..8869596f8 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index 6e9496ba3..85d5ebd92 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 aggregator-microservices diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index 87a1ebb5e..e24613b66 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index c29932fae..18771f343 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index 48bfff9c3..9222751d9 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index 24e9663aa..a5d5aad37 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index d912df965..156804c5f 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 async-method-invocation diff --git a/bridge/pom.xml b/bridge/pom.xml index a7a3883c8..d1a3f0e88 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 bridge diff --git a/builder/pom.xml b/builder/pom.xml index 6c171bef4..e63f68b96 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index c6f7e0c37..72ad13d03 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 business-delegate diff --git a/caching/pom.xml b/caching/pom.xml index c20842a89..3aa5c689e 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 caching diff --git a/callback/pom.xml b/callback/pom.xml index 4fe17d143..fa8b61478 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 callback diff --git a/chain/pom.xml b/chain/pom.xml index ee3b92401..7550e61c0 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 chain diff --git a/command/pom.xml b/command/pom.xml index a27a56e54..cfe40ce56 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 command diff --git a/composite/pom.xml b/composite/pom.xml index ace29d8d1..aace20b3a 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 composite diff --git a/dao/pom.xml b/dao/pom.xml index f64eff8bc..85338a263 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 dao diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index 7d1b83469..80679127f 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 data-mapper diff --git a/decorator/pom.xml b/decorator/pom.xml index 7ba2a4ee8..9991fdfe3 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index 2fca225b8..ccfe13348 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index 88ccdd2d4..e04add78b 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index 239bcf870..882ac218e 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index 4f31b2e7e..9be737c4c 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index b7de6e01b..91294b125 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 event-aggregator diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index 99ed39891..972b4982c 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 event-driven-architecture diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 60bb6d0ab..e46835d68 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 execute-around diff --git a/facade/pom.xml b/facade/pom.xml index e0e0f4a4d..db7de2cd6 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index 6c936de5c..00f9285d5 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index 5081ecf99..8d720eb28 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index 78c182af9..6db201fb3 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index ca5e115d0..0dfe5d7a9 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index c07cca157..27ee4f408 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index 959fa5548..a153f97cc 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index 2a448cffe..ba6dcbe83 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 front-controller diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index 076dfb44d..afe4e8c74 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index ce1a7049a..004554e6b 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index 6bb6f95cc..d30d28e1e 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index 9f5dd31f3..051ec1c15 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 484030a33..98c9f8834 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 iterator diff --git a/layers/pom.xml b/layers/pom.xml index bf155b655..5af14908b 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index fe6d44c78..056d3b579 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 lazy-loading diff --git a/mediator/pom.xml b/mediator/pom.xml index a6cdd028e..a01cf152a 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 mediator diff --git a/memento/pom.xml b/memento/pom.xml index a320f186c..7c58fb361 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 memento diff --git a/message-channel/pom.xml b/message-channel/pom.xml index cbeba7a75..2b3c2e01e 100644 --- a/message-channel/pom.xml +++ b/message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 message-channel diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index 3c01f6e8d..32b9d5b75 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 0aad02b27..6a4335280 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 model-view-presenter model-view-presenter diff --git a/monad/pom.xml b/monad/pom.xml index 7f128272d..4e9b36842 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 monad diff --git a/monostate/pom.xml b/monostate/pom.xml index 64ee52abe..80f8f919b 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index 0b835ed4d..1d097a064 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index c138c5ed4..00a4dff5d 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index 852006cd4..529652ea6 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 119416694..763440cc4 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0-SNAPSHOT + 1.13.0 naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index 46b281468..ca2f4af86 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0-SNAPSHOT + 1.13.0 naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index dccaf64a3..f7bf1a1b5 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0-SNAPSHOT + 1.13.0 naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index d416f2a72..bc99d852c 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -15,7 +15,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 naked-objects @@ -367,17 +367,17 @@ ${project.groupId} naked-objects-dom - 1.13.0-SNAPSHOT + 1.13.0 ${project.groupId} naked-objects-fixture - 1.13.0-SNAPSHOT + 1.13.0 ${project.groupId} naked-objects-webapp - 1.13.0-SNAPSHOT + 1.13.0 diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 762438aca..64aa036e3 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0-SNAPSHOT + 1.13.0 naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index b0adad1af..2cd0a14f4 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 null-object diff --git a/object-pool/pom.xml b/object-pool/pom.xml index 666242d1d..dcb293bb3 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 object-pool diff --git a/observer/pom.xml b/observer/pom.xml index 847a7ea89..8fb018214 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 observer diff --git a/page-object/pom.xml b/page-object/pom.xml index e6f888b05..93a81d648 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 page-object diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index 9717f5e13..5cf56e3e9 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 poison-pill diff --git a/pom.xml b/pom.xml index fcf1671c8..ebb75aa9d 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 pom 2014 diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index 20484245b..b26d31420 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index a72aa2c96..da849a753 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index ca12515ee..e8b129b00 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 promise diff --git a/property/pom.xml b/property/pom.xml index 1e9d0f0c2..fc000c41b 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 property diff --git a/prototype/pom.xml b/prototype/pom.xml index e8bb4303a..308bf91db 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index f16736a2c..8b4191e98 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 proxy diff --git a/publish-subscribe/pom.xml b/publish-subscribe/pom.xml index 6db6b3538..73476a966 100644 --- a/publish-subscribe/pom.xml +++ b/publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 publish-subscribe diff --git a/reactor/pom.xml b/reactor/pom.xml index c06584c6f..62ffe374d 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index 2df3d5b14..417877b9c 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 56a448ec5..304a620ee 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index 7b411f46c..549fe3cbd 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 resource-acquisition-is-initialization diff --git a/semaphore/pom.xml b/semaphore/pom.xml index 1b3bf8b5d..5f0f1c9cd 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 semaphore diff --git a/servant/pom.xml b/servant/pom.xml index c235b005c..145b726c3 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 servant diff --git a/service-layer/pom.xml b/service-layer/pom.xml index 23d788595..da8fe17fe 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index 0f17b3dcc..e0eff0e38 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 service-locator diff --git a/singleton/pom.xml b/singleton/pom.xml index ab9405c5e..d549025fd 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 singleton diff --git a/specification/pom.xml b/specification/pom.xml index 03c66540d..e3fcdd86e 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 specification diff --git a/state/pom.xml b/state/pom.xml index 134fbabe1..3c481c4e1 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index 96098eabc..7d39dad57 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.13.0-SNAPSHOT + 1.13.0 step-builder diff --git a/strategy/pom.xml b/strategy/pom.xml index e6fa58081..3902a1871 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 strategy diff --git a/template-method/pom.xml b/template-method/pom.xml index ee533df8f..1eeb18369 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index e7fa43103..19031bc23 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 thread-pool diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index e5dd3ba88..101673c9f 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 tolerant-reader diff --git a/twin/pom.xml b/twin/pom.xml index 1eb854b87..df839bf58 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 twin diff --git a/value-object/pom.xml b/value-object/pom.xml index ec8de1681..c2012093a 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index 54a90e184..39c7b45e5 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.13.0 visitor From 4ca205c03cc03ea5bc80fe27c0a4594f0d087582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 30 Sep 2016 19:40:28 +0300 Subject: [PATCH 074/492] Set version number for next development iteration --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- command/pom.xml | 2 +- composite/pom.xml | 2 +- dao/pom.xml | 2 +- data-mapper/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- execute-around/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- message-channel/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- publish-subscribe/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- singleton/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strategy/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- twin/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 92 files changed, 95 insertions(+), 95 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index be9aa68b9..1ab6d5a2b 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index 1d54f0c86..5c3d4d16a 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT abstract-factory diff --git a/adapter/pom.xml b/adapter/pom.xml index d8414f85d..83a930653 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 46d7d72c7..520aefaa8 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index 5d2d97fe6..4cd1916c6 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index 8869596f8..1bf655b45 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index 85d5ebd92..cedc35eec 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 aggregator-microservices diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index e24613b66..e2ab9e6d9 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index 18771f343..db25b947b 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index 9222751d9..94f91cabb 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index a5d5aad37..ce47e9db0 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index 156804c5f..e374b4753 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT async-method-invocation diff --git a/bridge/pom.xml b/bridge/pom.xml index d1a3f0e88..4960dbd08 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT bridge diff --git a/builder/pom.xml b/builder/pom.xml index e63f68b96..030990fa2 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index 72ad13d03..2b0ce9119 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT business-delegate diff --git a/caching/pom.xml b/caching/pom.xml index 3aa5c689e..07347e5c7 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT caching diff --git a/callback/pom.xml b/callback/pom.xml index fa8b61478..70dd8e5e2 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT callback diff --git a/chain/pom.xml b/chain/pom.xml index 7550e61c0..5593d3e73 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT chain diff --git a/command/pom.xml b/command/pom.xml index cfe40ce56..406c6d100 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT command diff --git a/composite/pom.xml b/composite/pom.xml index aace20b3a..48d693d2f 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT composite diff --git a/dao/pom.xml b/dao/pom.xml index 85338a263..e414f2b27 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT dao diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index 80679127f..eb342e9eb 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT data-mapper diff --git a/decorator/pom.xml b/decorator/pom.xml index 9991fdfe3..36c3eef01 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index ccfe13348..ed5f6608e 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index e04add78b..ab4619b63 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index 882ac218e..27c97479a 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index 9be737c4c..5093cced8 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index 91294b125..29d99ca2b 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT event-aggregator diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index 972b4982c..149ca7409 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT event-driven-architecture diff --git a/execute-around/pom.xml b/execute-around/pom.xml index e46835d68..115c201cb 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT execute-around diff --git a/facade/pom.xml b/facade/pom.xml index db7de2cd6..7816d51e6 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index 00f9285d5..32705cc46 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index 8d720eb28..74dc91a02 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index 6db201fb3..eebc433e8 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index 0dfe5d7a9..b438103e4 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index 27ee4f408..50f5d395a 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index a153f97cc..eb168c486 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index ba6dcbe83..c08ed8d0f 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT front-controller diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index afe4e8c74..d22e65a5e 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index 004554e6b..c489c45c4 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index d30d28e1e..487ac1c14 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index 051ec1c15..e2c8f4d4d 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 98c9f8834..6d589b4a7 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT iterator diff --git a/layers/pom.xml b/layers/pom.xml index 5af14908b..811f5e050 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index 056d3b579..d70587395 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT lazy-loading diff --git a/mediator/pom.xml b/mediator/pom.xml index a01cf152a..e3b227237 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT mediator diff --git a/memento/pom.xml b/memento/pom.xml index 7c58fb361..3dc7e5f52 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT memento diff --git a/message-channel/pom.xml b/message-channel/pom.xml index 2b3c2e01e..7c1825b5e 100644 --- a/message-channel/pom.xml +++ b/message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT message-channel diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index 32b9d5b75..38e756313 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 6a4335280..6fb7ab31e 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT model-view-presenter model-view-presenter diff --git a/monad/pom.xml b/monad/pom.xml index 4e9b36842..482cf4e4d 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT monad diff --git a/monostate/pom.xml b/monostate/pom.xml index 80f8f919b..d42870a17 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index 1d097a064..28e208d0c 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index 00a4dff5d..cae190e86 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index 529652ea6..b53587aa3 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 763440cc4..7e16ca000 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0 + 1.14.0-SNAPSHOT naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index ca2f4af86..f31b10fe2 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0 + 1.14.0-SNAPSHOT naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index f7bf1a1b5..547e88268 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0 + 1.14.0-SNAPSHOT naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index bc99d852c..344a234ac 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -15,7 +15,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT naked-objects @@ -367,17 +367,17 @@ ${project.groupId} naked-objects-dom - 1.13.0 + 1.14.0-SNAPSHOT ${project.groupId} naked-objects-fixture - 1.13.0 + 1.14.0-SNAPSHOT ${project.groupId} naked-objects-webapp - 1.13.0 + 1.14.0-SNAPSHOT diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 64aa036e3..1a729ade9 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.13.0 + 1.14.0-SNAPSHOT naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index 2cd0a14f4..832337772 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT null-object diff --git a/object-pool/pom.xml b/object-pool/pom.xml index dcb293bb3..927570b66 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT object-pool diff --git a/observer/pom.xml b/observer/pom.xml index 8fb018214..48909e1aa 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT observer diff --git a/page-object/pom.xml b/page-object/pom.xml index 93a81d648..207d04092 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT page-object diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index 5cf56e3e9..432f19547 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT poison-pill diff --git a/pom.xml b/pom.xml index ebb75aa9d..144b8efff 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT pom 2014 diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index b26d31420..1dc545cb1 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index da849a753..5ac018f51 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index e8b129b00..30a719f13 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT promise diff --git a/property/pom.xml b/property/pom.xml index fc000c41b..af0c9f288 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT property diff --git a/prototype/pom.xml b/prototype/pom.xml index 308bf91db..d0c03c0b6 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index 8b4191e98..7484fc47e 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT proxy diff --git a/publish-subscribe/pom.xml b/publish-subscribe/pom.xml index 73476a966..de5b6068b 100644 --- a/publish-subscribe/pom.xml +++ b/publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT publish-subscribe diff --git a/reactor/pom.xml b/reactor/pom.xml index 62ffe374d..5bb577c42 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index 417877b9c..f10acb8d7 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 304a620ee..45f735b7a 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index 549fe3cbd..ef5de7532 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT resource-acquisition-is-initialization diff --git a/semaphore/pom.xml b/semaphore/pom.xml index 5f0f1c9cd..4ee0edb9f 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT semaphore diff --git a/servant/pom.xml b/servant/pom.xml index 145b726c3..1e99bc09b 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT servant diff --git a/service-layer/pom.xml b/service-layer/pom.xml index da8fe17fe..830ced4f6 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index e0eff0e38..894908f92 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT service-locator diff --git a/singleton/pom.xml b/singleton/pom.xml index d549025fd..2ba9fe6d4 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT singleton diff --git a/specification/pom.xml b/specification/pom.xml index e3fcdd86e..49e56f3c1 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT specification diff --git a/state/pom.xml b/state/pom.xml index 3c481c4e1..ec932532d 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index 7d39dad57..cd53119ff 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.13.0 + 1.14.0-SNAPSHOT step-builder diff --git a/strategy/pom.xml b/strategy/pom.xml index 3902a1871..e57f42e08 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT strategy diff --git a/template-method/pom.xml b/template-method/pom.xml index 1eeb18369..2098a801f 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index 19031bc23..e1f9a4e49 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT thread-pool diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index 101673c9f..9668b5fb3 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT tolerant-reader diff --git a/twin/pom.xml b/twin/pom.xml index df839bf58..56fe7bd8a 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT twin diff --git a/value-object/pom.xml b/value-object/pom.xml index c2012093a..156d5b969 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index 39c7b45e5..e1d3ca6a1 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0 + 1.14.0-SNAPSHOT visitor From 9512f3ec701a8236ee2bf07bedd9ff9cb15aa154 Mon Sep 17 00:00:00 2001 From: Dmitry Avershin Date: Mon, 3 Oct 2016 21:59:36 +0200 Subject: [PATCH 075/492] Closes #436. Adds criticism to service locator pattern. --- service-locator/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/service-locator/README.md b/service-locator/README.md index 31d82b13f..75a00ca57 100644 --- a/service-locator/README.md +++ b/service-locator/README.md @@ -33,6 +33,13 @@ improves the performance of application to great extent. * lookups of services are done quite frequently * large number of services are being used +## Consequences + +* Violates Interface Segregation Principle (ISP) by providing pattern consumers with an access +to a number of services that they don't potentially need. +* Creates hidden dependencies that can break the clients at runtime. +* Limits object composability by stopping the clients to specify needed dependencies for different objects instantiation. + ## Credits * [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2) From 12544caa759fa1ac0fec7bd5bde5dae9d7a4a082 Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 3 Oct 2016 21:05:11 +0100 Subject: [PATCH 076/492] Changes based on review feedback. --- event-asynchronous/README.md | 2 +- .../com/iluwatar/event/asynchronous/App.java | 12 ++--- .../iluwatar/event/asynchronous/Event.java | 2 +- .../asynchronous/EventAsynchronousTest.java | 52 +++++++++++++++++++ 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/event-asynchronous/README.md b/event-asynchronous/README.md index dde434aba..ef35d0b38 100644 --- a/event-asynchronous/README.md +++ b/event-asynchronous/README.md @@ -3,7 +3,7 @@ layout: pattern title: Event-based Asynchronous folder: event-asynchronous permalink: /patterns/event-asynchronous/ -categories: Other +categories: Concurrency tags: - difficulty-intermediate - performance diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java index 65ae02e56..5a2565940 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java @@ -106,23 +106,23 @@ public class App { try { // Create an Asynchronous event. int aEventId = eventManager.createAsync(60); - System.out.println("Event [" + aEventId + "] has been created."); + System.out.println("Async Event [" + aEventId + "] has been created."); eventManager.start(aEventId); - System.out.println("Event [" + aEventId + "] has been started."); + System.out.println("Async Event [" + aEventId + "] has been started."); // Create a Synchronous event. int sEventId = eventManager.create(60); - System.out.println("Event [" + sEventId + "] has been created."); + System.out.println("Sync Event [" + sEventId + "] has been created."); eventManager.start(sEventId); - System.out.println("Event [" + sEventId + "] has been started."); + System.out.println("Sync Event [" + sEventId + "] has been started."); eventManager.status(aEventId); eventManager.status(sEventId); eventManager.cancel(aEventId); - System.out.println("Event [" + aEventId + "] has been stopped."); + System.out.println("Async Event [" + aEventId + "] has been stopped."); eventManager.cancel(sEventId); - System.out.println("Event [" + sEventId + "] has been stopped."); + System.out.println("Sync Event [" + sEventId + "] has been stopped."); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java index c2e14ad68..5e557fff2 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java @@ -75,7 +75,7 @@ public class Event implements IEvent, Runnable { long endTime = currentTime + (eventTime * 1000); while (System.currentTimeMillis() < endTime) { try { - Thread.sleep(5000); // Sleep for 5 seconds. + Thread.sleep(1000); // Sleep for 1 second. } catch (InterruptedException e) { return; } diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java index 6565d5bad..92bacda99 100644 --- a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java @@ -79,4 +79,56 @@ public class EventAsynchronousTest { System.out.println(e.getMessage()); } } + + @Test + public void testFullSynchronousEvent() { + EventManager eventManager = new EventManager(); + try { + int eventTime = 5; + + int sEventId = eventManager.create(eventTime); + assertTrue(eventManager.getEventPool().size() == 1); + eventManager.start(sEventId); + + long currentTime = System.currentTimeMillis(); + long endTime = currentTime + (eventTime + 5 * 1000); // +5 to give a bit of buffer time for event to complete + // properly. + while (System.currentTimeMillis() < endTime) { + } + + assertTrue(eventManager.getEventPool().size() == 0); + + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException + | InvalidOperationException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void testFullAsynchronousEvent() { + EventManager eventManager = new EventManager(); + try { + int eventTime = 5; + + int aEventId1 = eventManager.createAsync(eventTime); + int aEventId2 = eventManager.createAsync(eventTime); + int aEventId3 = eventManager.createAsync(eventTime); + assertTrue(eventManager.getEventPool().size() == 3); + + eventManager.start(aEventId1); + eventManager.start(aEventId2); + eventManager.start(aEventId3); + + long currentTime = System.currentTimeMillis(); + long endTime = currentTime + (eventTime + 5 * 1000); // +5 to give a bit of buffer time for event to complete + // properly. + while (System.currentTimeMillis() < endTime) { + } + + assertTrue(eventManager.getEventPool().size() == 0); + + } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { + System.out.println(e.getMessage()); + } + } } From 622376e0fa3b1723b86853c4c8a882b6bd378cb2 Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 3 Oct 2016 21:16:23 +0100 Subject: [PATCH 077/492] Updated version snapshot to 1.14.0 --- event-asynchronous/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index 60ab8f0aa..1bc4549d4 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.13.0-SNAPSHOT + 1.14.0-SNAPSHOT event-asynchronous From 8f1758c28f663f73ea79be8d2a1575fcc4d9fffe Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 3 Oct 2016 21:46:16 +0100 Subject: [PATCH 078/492] Alter JUnit tests to run in lesser time. --- .../event/asynchronous/EventAsynchronousTest.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java index 92bacda99..213439203 100644 --- a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java @@ -84,15 +84,16 @@ public class EventAsynchronousTest { public void testFullSynchronousEvent() { EventManager eventManager = new EventManager(); try { - int eventTime = 5; + int eventTime = 1; int sEventId = eventManager.create(eventTime); assertTrue(eventManager.getEventPool().size() == 1); eventManager.start(sEventId); long currentTime = System.currentTimeMillis(); - long endTime = currentTime + (eventTime + 5 * 1000); // +5 to give a bit of buffer time for event to complete - // properly. + long endTime = currentTime + (eventTime + 2 * 1000); // +2 to give a bit of buffer time for event to + // complete + // properly. while (System.currentTimeMillis() < endTime) { } @@ -108,7 +109,7 @@ public class EventAsynchronousTest { public void testFullAsynchronousEvent() { EventManager eventManager = new EventManager(); try { - int eventTime = 5; + int eventTime = 1; int aEventId1 = eventManager.createAsync(eventTime); int aEventId2 = eventManager.createAsync(eventTime); @@ -120,7 +121,7 @@ public class EventAsynchronousTest { eventManager.start(aEventId3); long currentTime = System.currentTimeMillis(); - long endTime = currentTime + (eventTime + 5 * 1000); // +5 to give a bit of buffer time for event to complete + long endTime = currentTime + (eventTime + 2 * 1000); // +2 to give a bit of buffer time for event to complete // properly. while (System.currentTimeMillis() < endTime) { } From eea8785a22527899da48c56f64b63aa0db1df1b5 Mon Sep 17 00:00:00 2001 From: Dmitry Avershin Date: Tue, 4 Oct 2016 14:34:01 +0200 Subject: [PATCH 079/492] Fixes #437. Adds criticism to Singleton pattern. --- singleton/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/singleton/README.md b/singleton/README.md index e1bb42a45..38a05349b 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -36,6 +36,11 @@ Use the Singleton pattern when * [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--) +## Consequences + +* Violates Single Responsibility Principle (SRP) by controlling their own creation and lifecycle. +* Encourages using a global shared instance which prevents an object and resources used by this object from being deallocated. + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) From 3a9d1684fd19b0987d8230031a6b05efd6abb0cc Mon Sep 17 00:00:00 2001 From: igeligel Date: Tue, 4 Oct 2016 22:33:06 +0200 Subject: [PATCH 080/492] Initial commit of the object mother #498 Add a simple king and queen classes which implement the behaviour of the royalty interface. Also wrote the object mother of royalty objects which is final so you can just call the static methods in it to create objects with a specific state to use them fast in tests. The tests are already created for testing the behaviour and the type of the objects which are created by the object mother. I also created the UML diagrams via object aid and updated the readme. --- object-mother/README.md | 31 ++++++ object-mother/etc/object-mother.png | Bin 0 -> 19705 bytes object-mother/etc/object-mother.ucls | 56 +++++++++++ object-mother/pom.xml | 48 ++++++++++ .../java/com/iluwatar/objectmother/King.java | 66 +++++++++++++ .../java/com/iluwatar/objectmother/Queen.java | 69 ++++++++++++++ .../com/iluwatar/objectmother/Royalty.java | 33 +++++++ .../objectmother/RoyaltyObjectMother.java | 83 ++++++++++++++++ .../test/RoyaltyObjectMotherTest.java | 89 ++++++++++++++++++ 9 files changed, 475 insertions(+) create mode 100644 object-mother/README.md create mode 100644 object-mother/etc/object-mother.png create mode 100644 object-mother/etc/object-mother.ucls create mode 100644 object-mother/pom.xml create mode 100644 object-mother/src/main/java/com/iluwatar/objectmother/King.java create mode 100644 object-mother/src/main/java/com/iluwatar/objectmother/Queen.java create mode 100644 object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java create mode 100644 object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java create mode 100644 object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java diff --git a/object-mother/README.md b/object-mother/README.md new file mode 100644 index 000000000..9188c8b41 --- /dev/null +++ b/object-mother/README.md @@ -0,0 +1,31 @@ +--- +layout: pattern +title: Object Mother +folder: object-mother +permalink: /patterns/object-mother/ +pumlid: +categories: Creational +tags: + - Java + - Difficulty-Beginner +--- + +## Object Mother +Define a factory of immutable content with separated builder and factory interfaces. + +![alt text](./etc/object-mother.png "Object Mother") + +## Applicability +Use the Object Mother pattern when + +* You want consistent objects over several tests +* you want to reduce code for creation of objects in tests +* every test should run with fresh data + +## Credits + +* [Answer by David Brown](http://stackoverflow.com/questions/923319/what-is-an-objectmother) to the stackoverflow question: [What is an ObjectMother?](http://stackoverflow.com/questions/923319/what-is-an-objectmother) + +* [c2wiki - Object Mother](http://c2.com/cgi/wiki?ObjectMother) + +* [Nat Pryce - Test Data Builders: an alternative to the Object Mother pattern](http://www.natpryce.com/articles/000714.html) \ No newline at end of file diff --git a/object-mother/etc/object-mother.png b/object-mother/etc/object-mother.png new file mode 100644 index 0000000000000000000000000000000000000000..807343d9f9e42c2b3f306beb5c8e2199bbedafb1 GIT binary patch literal 19705 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 literal 0 HcmV?d00001 diff --git a/object-mother/etc/object-mother.ucls b/object-mother/etc/object-mother.ucls new file mode 100644 index 000000000..ef6cee5ef --- /dev/null +++ b/object-mother/etc/object-mother.ucls @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/object-mother/pom.xml b/object-mother/pom.xml new file mode 100644 index 000000000..91bdff8e2 --- /dev/null +++ b/object-mother/pom.xml @@ -0,0 +1,48 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.14.0-SNAPSHOT + + object-mother + + + junit + junit + test + + + org.mockito + mockito-core + test + + + \ No newline at end of file diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/King.java b/object-mother/src/main/java/com/iluwatar/objectmother/King.java new file mode 100644 index 000000000..544b0bacb --- /dev/null +++ b/object-mother/src/main/java/com/iluwatar/objectmother/King.java @@ -0,0 +1,66 @@ +/** + * The MIT License + * Copyright (c) 2016 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.objectmother; + +public class King implements Royalty { + boolean isDrunk = false; + boolean isHappy = false; + + @Override + public void makeDrunk() { + isDrunk = true; + } + + @Override + public void makeSober() { + isDrunk = false; + } + + @Override + public void makeHappy() { + isHappy = true; + } + + @Override + public void makeUnhappy() { + isHappy = false; + } + + public boolean isHappy() { + return isHappy; + } + + /** + * Method to flirt to a queen. + * @param queen Queen which should be flirted. + */ + public void flirt(Queen queen) { + boolean flirtStatus = queen.getFlirted(this); + if (flirtStatus == false) { + this.makeUnhappy(); + } else { + this.makeHappy(); + } + + } +} diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java b/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java new file mode 100644 index 000000000..3e18fbf3a --- /dev/null +++ b/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java @@ -0,0 +1,69 @@ +/** + * The MIT License + * Copyright (c) 2016 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.objectmother; + +public class Queen implements Royalty { + private boolean isDrunk = false; + private boolean isHappy = false; + private boolean isFlirty = false; + + @Override + public void makeDrunk() { + isDrunk = true; + } + + @Override + public void makeSober() { + isDrunk = false; + } + + @Override + public void makeHappy() { + isHappy = true; + } + + @Override + public void makeUnhappy() { + isHappy = false; + } + + public boolean isFlirty() { + return isFlirty; + } + + public void setFlirtiness(boolean flirtiness) { + this.isFlirty = flirtiness; + } + + /** + * Method which is called when the king is flirting to a queen. + * @param king King who initialized the flirt. + * @return A value which describes if the flirt was successful or not. + */ + public boolean getFlirted(King king) { + if (this.isFlirty && king.isHappy && !king.isDrunk) { + return true; + } + return false; + } +} diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java b/object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java new file mode 100644 index 000000000..2bebc0939 --- /dev/null +++ b/object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java @@ -0,0 +1,33 @@ +/** + * The MIT License + * Copyright (c) 2016 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.objectmother; + +public interface Royalty { + void makeDrunk(); + + void makeSober(); + + void makeHappy(); + + void makeUnhappy(); +} diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java new file mode 100644 index 000000000..624a29132 --- /dev/null +++ b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java @@ -0,0 +1,83 @@ +/** + * The MIT License + * Copyright (c) 2016 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.objectmother; + +public final class RoyaltyObjectMother { + + /** + * Method to create a sober and unhappy king. The standard paramters are set. + * @return An instance of {@link com.iluwatar.objectmother.King} with the standard properties. + */ + public static King createSoberUnhappyKing() { + return new King(); + } + + /** + * Method of the object mother to create a drunk king. + * @return A drunk {@link com.iluwatar.objectmother.King}. + */ + public static King createDrunkKing() { + King king = new King(); + king.makeDrunk(); + return king; + } + + /** + * Method to create a happy king. + * @return A happy {@link com.iluwatar.objectmother.King}. + */ + public static King createHappyKing() { + King king = new King(); + king.makeHappy(); + return king; + } + + /** + * Method to create a happy and drunk king. + * @return A drunk and happy {@link com.iluwatar.objectmother.King}. + */ + public static King createHappyDrunkKing() { + King king = new King(); + king.makeHappy(); + king.makeDrunk(); + return king; + } + + /** + * Method to create a flirty queen. + * @return A flirty {@link com.iluwatar.objectmother.Queen}. + */ + public static Queen createFlirtyQueen() { + Queen queen = new Queen(); + queen.setFlirtiness(true); + return queen; + } + + /** + * Method to create a not flirty queen. + * @return A not flirty {@link com.iluwatar.objectmother.Queen}. + */ + public static Queen createNotFlirtyQueen() { + return new Queen(); + } +} diff --git a/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java new file mode 100644 index 000000000..feba71a1b --- /dev/null +++ b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java @@ -0,0 +1,89 @@ +/** + * The MIT License + * Copyright (c) 2016 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.objectmother.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.iluwatar.objectmother.King; +import com.iluwatar.objectmother.Queen; +import com.iluwatar.objectmother.Royalty; +import com.iluwatar.objectmother.RoyaltyObjectMother; + +public class RoyaltyObjectMotherTest { + + @Test + public void unsuccessfulKingFlirt() { + King soberUnhappyKing = RoyaltyObjectMother.createSoberUnhappyKing(); + Queen flirtyQueen = RoyaltyObjectMother.createFlirtyQueen(); + soberUnhappyKing.flirt(flirtyQueen); + assertFalse(soberUnhappyKing.isHappy()); + } + + @Test + public void queenIsBlockingFlirtCauseDrunkKing() { + King soberUnhappyKing = RoyaltyObjectMother.createDrunkKing(); + Queen notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen(); + soberUnhappyKing.flirt(notFlirtyQueen); + assertFalse(soberUnhappyKing.isHappy()); + } + + @Test + public void queenIsBlockingFlirt() { + King soberUnhappyKing = RoyaltyObjectMother.createHappyKing(); + Queen notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen(); + soberUnhappyKing.flirt(notFlirtyQueen); + assertFalse(soberUnhappyKing.isHappy()); + } + + @Test + public void successfullKingFlirt() { + King soberUnhappyKing = RoyaltyObjectMother.createHappyKing(); + Queen flirtyQueen = RoyaltyObjectMother.createFlirtyQueen(); + soberUnhappyKing.flirt(flirtyQueen); + assertTrue(soberUnhappyKing.isHappy()); + } + + @Test + public void testQueenType() { + Royalty flirtyQueen = RoyaltyObjectMother.createFlirtyQueen(); + Royalty notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen(); + assertEquals(flirtyQueen.getClass(), Queen.class); + assertEquals(notFlirtyQueen.getClass(), Queen.class); + } + + @Test + public void testKingType() { + Royalty drunkKing = RoyaltyObjectMother.createDrunkKing(); + Royalty happyDrunkKing = RoyaltyObjectMother.createHappyDrunkKing(); + Royalty happyKing = RoyaltyObjectMother.createHappyKing(); + Royalty soberUnhappyKing = RoyaltyObjectMother.createSoberUnhappyKing(); + assertEquals(drunkKing.getClass(), King.class); + assertEquals(happyDrunkKing.getClass(), King.class); + assertEquals(happyKing.getClass(), King.class); + assertEquals(soberUnhappyKing.getClass(), King.class); + } +} From 863ea7538156398eba1d179e36e9379e5eeef968 Mon Sep 17 00:00:00 2001 From: igeligel Date: Thu, 6 Oct 2016 20:12:43 +0200 Subject: [PATCH 081/492] Add PlantUML file for the UML diagram #498 --- object-mother/etc/object-mother.urm.puml | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 object-mother/etc/object-mother.urm.puml diff --git a/object-mother/etc/object-mother.urm.puml b/object-mother/etc/object-mother.urm.puml new file mode 100644 index 000000000..9b26450f0 --- /dev/null +++ b/object-mother/etc/object-mother.urm.puml @@ -0,0 +1,45 @@ +@startuml +package com.iluwatar.objectmother { + class RoyaltyObjectMother { + + RoyaltyObjectMother() + + createDrunkKing() : King {static} + + createFlirtyQueen() : Queen {static} + + createHappyDrunkKing() : King {static} + + createHappyKing() : King {static} + + createNotFlirtyQueen() : Queen {static} + + createSoberUnhappyKing() : King {static} + } + class Queen { + - isDrunk : boolean + - isFlirty : boolean + - isHappy : boolean + + Queen() + + getFlirted(king : King) : boolean + + isFlirty() : boolean + + makeDrunk() + + makeHappy() + + makeSober() + + makeUnhappy() + + setFlirtiness(flirtiness : boolean) + } + interface Royalty { + + makeDrunk() {abstract} + + makeHappy() {abstract} + + makeSober() {abstract} + + makeUnhappy() {abstract} + } + class King { + ~ isDrunk : boolean + ~ isHappy : boolean + + King() + + flirt(queen : Queen) + + isHappy() : boolean + + makeDrunk() + + makeHappy() + + makeSober() + + makeUnhappy() + } +} +Queen ..|> Royalty +King ..|> Royalty +@enduml \ No newline at end of file From f114b5b957c8ef432a504b24a56efa36599a9017 Mon Sep 17 00:00:00 2001 From: Christoffer Hamberg Date: Sun, 9 Oct 2016 12:43:43 +0200 Subject: [PATCH 082/492] Caching pattern: Documentation and diagram --- caching/README.md | 1 + caching/etc/caching.png | Bin 56234 -> 114847 bytes caching/etc/caching.ucls | 190 ++++++++---------- .../main/java/com/iluwatar/caching/App.java | 23 ++- .../com/iluwatar/caching/CachingPolicy.java | 2 +- .../java/com/iluwatar/caching/LruCache.java | 3 - .../com/iluwatar/caching/UserAccount.java | 2 - 7 files changed, 101 insertions(+), 120 deletions(-) diff --git a/caching/README.md b/caching/README.md index 6432ffcea..b48d060f0 100644 --- a/caching/README.md +++ b/caching/README.md @@ -27,3 +27,4 @@ Use the Caching pattern(s) when * [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained) * [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177) +* [Cache-Aside](https://msdn.microsoft.com/en-us/library/dn589799.aspx) diff --git a/caching/etc/caching.png b/caching/etc/caching.png index 6b3b2d0556c51b7c593028b2c9120a00c47716c1..b6ed703ab8b7dfce5e5d82f097dac534828fc93a 100644 GIT binary patch literal 114847 zcmb5WbySsIyY`K-5SMgHNK1#(4U0wu=|&oqM!IFuASs}9hjfE$x5I=37`lF2q;pLq6!EIk5v&69$Fwh1Rrrj zLDEEc&}1wn3R7}Q*iC%uhT2KkDe{4?3jG{|pe?$3n<{`}p&YXa6l1$Ho4u2B`(d#kxT^kK}V!Ufx>p-(cUd zyQ9g3c#4qMLkJX`M(*$bm_a$#nGpW#@8BQ4v!O%e|LwDyYaYs@|JP@*`V(=R)5vvg ze>UyNOF&T;fMUPJZL5?>ghHUu=93O#@a2yYpEr=YiI5xpU>o1Hh)(a3Adh{kKbtP= zE2#*lFXAm}8YyNsA32mf;spEtn@r&5w35dPiNYu&okg)l$+u|JNTJyI zjB@@)<-~kkx@RnEK>_g6=$viMaPVhl7h;*PC=8oMO|$Fl#YDZU&MMJiygIMj&84W5 zQ{$(#H&Kk5L~U?X0r8Tk*WpEJ*miH7|Ft@Ss0_vd)zg<1qW(*GCVx{rntoSkehE_iNc{_+-iE zMT4>A<&1-J1*AMNAV$96i8BB7)dF8kwE9cQ%eVGK(Gox3bX|J`7f$SC;rXkSM01YAR0|8++naNNq))3IN%gMjK903yTf_>A zikBxJ_f}Tq(nOoPx?rWWG#t=_Ep=pS_@ff-ZYqt0062?;(y5eR5Dks37{~VzF>FyU zcmfELdoV=>gUF_74Hys?^)u*Eu{u{D=c)mm$(|I{Y+^oeVEg_l~u5R-l3X`e}z%6o#t%9GhAfPKS$p`k>efs z5evNKakNZN!B-)`VgF)}e|~V_=uqi-LbJ6sYN)E(S?h>pRA!TU@cZm6ijnZZ&+xq1 zVix&Chu3ky<@OqhGQPzZt9ffFV`Y^h3X4%p6o!wZ?Eb9a(ijiCl|b`Xv$LfCY%GSt z)|oOB*_%s&%r`jitF7C;$l*V*LJN`Mn)zuFjlUi?#U$v>=@O-7fNhSe*)94xv)Q2aGS5O zh8@dRm~&*|F)JMXD&hS^8JFGGDS=HJc?Xtn0i}EY0sj7ijOgp3FefMM&`@Fu8Ey|Z z2sBI){XmCfctsRD>SJ2&I~GY%SS(X%^Df=LUX`7{{q`8o#Edl7@J}{VrM<&d5qi~7 zdc`cRk&OWqi`h!Als{z*uZF(86z)LEu8(X6B;Mb(wp}y z2q*bzn&2vUYc8iwf{g^sI>aLS!MGJeTat=$=GgCdtV;uNslgKAg438p4(%b2Krt4? z00l_bf~?j-&GCS$(p;VT9WgH+-V=_%f&O^cTxI%=y*>4YItfwHfOG@m+aqB)xiZuj z1SQqN9EGn9Ts(fm5XcM{yxp~8orM~)65zZfizuq z;D^Tyrs+B%CoGry*LQVwR0ErE@^Y*>kvH(t?OG_=d^a8iac_CLtW{$)f#gbI$^5}tv#2AnWNtYm+fQJyXXaE1ooEVE&09=ytIDjTV zbOcnXTomq4Q*y=YpP}Jm%DsL(3zreLNYvAfWr6xh+EfOd$dpQ$BoK)WPT_ zSoxGLg?x$o?>L>WOomUFmzhFai<`3ZRGox}N{<0+WjwnaR--Zib{gqg)E9dCvyUj` zP=#+NRrE~Yz|*CreCeu-X>oYDFbis^I`m47j@DKTJ7Xq1Q3EFuqf{0uETL$j5Zql$ zWiD91)>Y&ms>2<$_#KO$YA@~=cTK7aXIsYrzo&-}lN4tXe9VqKp`}X$gd#O=y zeElnEsW9~N>?Dw9bk;NG)%sHVjfRncHJQzIs0~;HjK=S}522=@Knx^&^xv8&h@CD9 zQ)>_UnXY7do1H`>$;dKR_+3f!RB9`Tri&|fUg0@pdS<=tpw78fO+S$*S`8{MrxHLT zSwV)SiK8}gwx@G_;F%YVRR)J!E-sjzy z9-hA+N}k(s|C^YAmeuP1xN*Z^*R#H6eZya*ZSt?$Tu**4mVY#D56V1Rv+YQ-3H^wd z>uQUQOs)AtVXLj}k8z{TmWnPoQay6Dn0Bf+)bAqYX|K+$2w(7bjFzb#u0V_ji6i&v zA_K*+4HNn-X}`eV#4!9?U!N;AdI1|{ec+X=!bqQ$a?lv|6l$tcoI+R$@qVo;p4vK8 z@s!>(p5t_waXfG1=5+G7#9uyLKtJ!~fR<6?e#gg-WCQ3WU%mHJa26%Ra}Mkc z)pD!F@C_gOzywB(u^Kn$_#!Lii*L3Yex(WB-O_dS{CbUC7!wx>0xxE39T7CbfK+KB ziN;0iM|z`NX?~b4kzVqyfn@hVM`*_b3wWXMiUt{>2BQ|gmPloRd0LN!V#N!U%s8olSn}wJ8>JpivH+kB%+4@!R{HozW~30VVxO#tz4>!Q?BMWom>xkg92F4@n-^I- zUWf((cUd)6q74J%3ByywvnX7~G}3WD&wzOG~swBpAPlwgvs%;N%J3aC-D8m zwHcBHr^8dJHBO_du=7*PQ_Tjqd~*&aW-kY|3Z1v-LHx2$h<1-??9HhQ>o1`X#b zYg1-rFnC*(qJ$9z7Aj;S_XeIlu;@K#^bEvybW~NF`=PiaMD>BFNwxTVYRY<-nyY&J z_wsykcOVx1aIug7`D}$5c(wbBi(v}OJfAD32yL34o0wd&n+Y_!*i-i<8+~P@#B#Vg z?A)_Kv3ZHlvh_x(z#_M@HCG^0COWV`9X0C)%kku>Y5^-w`L>SMNAk3r(MxoK=-NnYG z;dDw4b>Q!5w zGJSSkkfA;X1fRN06PisrF-QH95q{^@HBm6i4QUQk2a+dCMiJxg>cE|$F=a|`bLO!n z`c8=&brA8hVC`BC9OT`99aMaCqtJMHFjYliIx2RS6`1yGNNPj`{Z zKbxX8_K%Mr?$3)(n``xr+}xN|nN5D)8hyw6l%T0;o#EZ5qsSl}>8CZcNTC$cM6c6a zL1|DY+Cx?mlL-3(c47~Lc1?LZQ0OVCq~U12RGNIZ;zT5PY>t*6=4+y-six2-T1=uD zDe)ZOW&!m0BqXT`IkK}#7XIUWxvKT}dmWU0LS%P!p8bx-{(h`8B0CK-Q=d##hkD2u z)8K7)ZEFLGXDZL>C^aAN6?ZZOcyms9>LFFTf2Bqf8pmNP$|TEFDF|vZ4hSjyvs09q zZ{cWTv&7r!ZsO^aDlDAC$YJH*xPm*|Ri9BnpLmmqhyL3y(`$kwj?A`5CwV9><#dPo zqda=i;Fq1tbE{t5K)B>3sHh4#f6tns)l8H5(w`EZ+~R+KCDkkeU+_ndz0rbV7}Sx7 z1FOxvY_SLlQ9saXagmG!uaXDj=4Zxag5-_|Sycyk{&N;h0t%KZHF z(#Mf@^Y?OQ0-TROxI~mFps_&Xhr&lTjAYM+CugA|w#~v30}eTPP6|*c%3eFtk&-EQ4K3D6!`>ap`lSO>+PX& zzv-u&%N>=8$}+*O?=C05t0Eqsl{VGbe@uk9(kd}%Z-I$OjK`r1x7k3b;(VdkcczOb zM>68te0+O+wSuN=em=Tjrs3vU8foNfpb4;Z1ss>u`bAE~lq<`6Lnc)8qNj^KR{#}y zFA}&QdeNZPQQ#7Zy@hRVd={^)-@)ojus6$Qq_>}P(Mfz4*WEp!{S3uM@^0H2e! zP-S>$SWy#BtNs1lL88hbzgGEU26bn4l$uY1bGN*F(B$b?=7om7XKpvk{nJly5gB*F zDpv4aK>M>0wbC!+NSNOY##@ztfKa|E({St3ke6q$KUcY=JQ1HlP$ttvUER1Tpf)=| zzkG9bb^NQuTi~{uf3(SKujC2GHI9k_h0FAl7cxLn4J2t7(cc`cSx7R=kutj?_SO)q zblZH`{mPHmLO%6A7+#Ds8;=WlkYFxq^(a?P6lNL$bI8;>{nN|$;liit&bRDLUJs|c z4G2kD<0@=fSOBM`R)~>zFjZCx7=>p(h(pOd&Mh?>UuKa`ql!#Y1+=aI;2r_darXvqw%Bfbh)!EA(~gd0v2btgxehB_AG}*{Dsc>b~EE!?1~XrFYQ%Hu*M?^k^?5Pm&5(K75#^C^LXIz>{k8 z`VZG@i2Kc{TiY__OG;71$72=FR~~V~{;6hI0WzzPItONFzt-yy&`1s@u@K(N>}JCP z=u(DJFVAQ6DM-8(G+eGggZnw;n$^h|Xrqf-TNtdL$L>Sh3Usr;yM1zf9iMv|(rDITagSw8eA2TlF;QOW=MU`Vq*};tlC< zl}J1^G_zA#J-iHdYywzuj%p)Sy+^m&F{ho(E0V*)q_AT{G=8xLw}E_zW!$jm!-;~# z4-g*-hofrjPnEn*Zv8!LrTQQ+;&#FHXB^uPkG&Zt*hppBw9SxF09vPbPTI`pJkMKa z#r`-PbGFe2J!&E`yG%h3Hze)n-b8jx(%(YYYmLHk!{67~MZA<2-;#ojX1Vtb5X67K ziRliak<=a;EsV;$O_z}3h{MlBL^V&QkeCrfCvhKxhx8dRHthbD*HIX;!wPNK<(_vB zK_oMtHc1tabwH_PEgL&T1d$8pHSogMq z9&m0e1YEpl3I|QBPx`XLfY4|%shU(YAHWm|e)3I;{v|uRn6qHkw{eB=6zA8eiYF=J ztln{b+o6lZ^sO1mxuZ3`o;MYW4&y+Vetp5`Et4_cB-d|~mm9z<|? zO6LHLJ+&{&M+ft)VUD&`I}z7Xovv!HoH+f=&h0<4Cb!8XCgwtaN2iV`ItWkmFuokKQY+Eys-4DiiM#@$j?~m+E;J zXORay5X1TgybWXr5iqY=%~ry2qvd8$N?77=MvMUW?V|u7Cyn$Na5=c>J*^Nc=phlz zV%Sx6K5t14|9x4ZW`b(2#+$Wvy>zsqy2@es_A0J8+oZ&1)ul+Ax5R8ROD$ieV6M!> zKP1nphUUZm+z>c;M!&|MLjVn9;c@93`|&6kyF08sk=KOQ>Lpe3mv3ZPM*Y|)M{6aZ zS^_Ax36V|Gy1M=oK_JE*DNWTd3st9Bw1$6elUMUAVI5I*!I(wFk+<6xj&xs+-_@SGE3%$ zPPs=nSyB`~2**~UqS4c{aUyqbwoyp0Cx)>BobzcGY0lxE&z49w3E#rPHsaWmk6Bj7 zfa;NOE?&-6UWLeULdfv@YNH|!H<-|=Ngks=)r;*f=A0I?iUfcx)DWD6npa(JV z{t)FT2fkP|HgJ-lLKJLFm~toAdrM8CeC%j%UtZDg{O5=x=4gBT5QC!T z5i8)7Z7b)CosS{x^lC!|PKOWoX4tF2?A3eUNCBK^@sa*d?67o-f?W=1GILSn{(hmJ z9_+^ttAO6w*)rH864CdK0`fnPo)n8teFU`OGtCr^C)Pnn2>&Y!z$jc!>l$xe1U?;Q zSAT&g@i`wmii?UO;a;75?8hBOAJ12RK*(XPwia)ta`cQmi}XFBb~ZZE98`kOW~G0< z%owFvAAsTBQkhdnH9*V{W;ypdz@Z51;cz_*Z}#TZKRny3Ck0sc9qx>^sP!Se(r=+( zL#gf8@1GqsL^j<;ig5Y_`6GoB6B2V{hFBu;cFI3|~6(5fJB`SM$Sw6?O#V zHt7EO&sPC4D+T0z+>gOjImTVXWn;>X?l z+wH;F-vbl1_W?+KfEYfy*vO#?A#Wky%mKqlfVH>LK`t1is}!?45HJ~z-r?91JorF1 z-`!1I=fls-v))Yp_PbG@Hm`;M=dWmj3|3ZF{#>uV6ksY20Sn}G=SufAUmXeVFqABb zw~A4NOf>xX-eIxVDyZJ26%|7fAtLHJLKrFTPWId{W|&p-^k@HM=y*8$<>spD=BPK8 zA@u6DlVo;S1&w3@C0I%-_;VI~9cyZDmh)G9mxD+SVLl-burgk`?oPeetdg}FPE!HY z$&Maj_kF!arKR>kdYDEr&meG7=zdMQ1Zw2{UDYM*@RpUA(zuwS^XR-4lSS_UBNxxm zY2*MW43`bJ^OJ^80Q?ImQ_V+t4bx)SQ5X>@&1 zyMdxHl)aMnKzaT2Oh4A~Ajw;Q?1!S1gDSvlI+f-O`G|*&cMJXrnQt=H``-z+zxL3z z>IW2`=#?$#@+ynyQ)N-0QU(VK2gA`DZX9rM8!uKA+ge*jh~K#b09d)PF&I|NZ*X67 z%+bEUgK+H~ZEcNRt*xC%e1F>S(6@QLZM?gESt^r!`xKXuvoOnE%SLOGR;#gr*JOYw zUm46>51h9r3e0UPf83&)9W3Mw4Hd%I!|2A)?QnM&b3AXkzjGETnwmmA^YG`=;TqGq)F+DHH{Om>GS-fUb#XSH|HjNJf4e{Z6V-O9CEfG7f8%R)5L3n^2P7T?K zKGZ12GA$Z*tzQYC?uaudHXf&MY@pE%z67@6mz?cqF*<+kp)UdEa>Z1Hl=m&F#sv24 z>gv_&i$Aw{$~uhrs20cvT_b%@+|Gf=r(OqvY>S^bJMCdGu>KO^ops zs~W(16PreEZhZLmJKKIjbt_bf_9Bk^lrFBWl@_xpszouo9~)EtnB^OEmR|)gWN6ox zd(MRt1tN|jKB?NCEJEQ4^}OQ`+79U||41UOdT1FyBLB~3++0NAcaQs0CImr!_H5)- zSH%}hBjQS@klv!dW|p`p2aVcS6imnu4nz68QfJd4u+>z;etSQMyetaS4c5{b*dAm# z&ZYrf`jG!I;w3ODZ;l6Fs9iNb5d(f=OFk|m!BZca_jL#?`I>l49fSp!9VQY}U_cG! zg!{nf=Cw1YpAQyKc#}v5!!N2ynWorB0JAj-=ED2sc2KWnE^MI=R>*feuhT#oluTnO#}*yk?X(q0{4osr?4n*i=H54$tJ!5jUEp9s<+W(t5bIaY()r;X2cic72H z_Tt%oEHt>c0`Peh%RR=NMyeogl=`>2k{iX8*8lS+wDXQmdu(i7oy5@!-6<`z)DAI7 z7&jF$%-UlcuPpmr57vbBOvir1N6}=3o^utu&v-N>g;j@zQCE|brZBBAF`>c{4WCPlI93EE>#!^WMpTq7 zTcjX0)$XoEY&U>iYBT3AG&bHXx1KB-jq3oPP+SZ}S~9@!pr@lf(|uU^u81`|E9?4n zQr7$Zel))?z^qjmGS8C4z~ZQv|2LCuEVnDy#hzI!cD>&Wm1rtS=4~exoHZme5*PTO zp!F`c+B9C8TE-9u(*zg}gRcQtvRpag@s=&r{5vs4!KYY)!XL6}GhBR$3v^ zW)C?#(2*-ni3eg)z0A+>w4`)^V|s}Rie1W<5_dBhC%=|1)NBYdcg=cgIEl@`_I*K( zW)mOydik0hCkz3G-KD7}K*Fm>*(W}+r^_&>8YO%N;s3We2_N?|mPiqT4GNV}#pMx@ki0e>lPD=! zzVvL8pu4CB4*p;orsWKq{mCZr$i0^C?xCtxlnca!pb={^$Z~(8tT7!gtvMp$Djovn z&2q~hpwkQA&+nXUsl^D`=l6Z~hE}t(divc^kCDhA7(dErc6iXD9qA||Q(5Xu zQOT|5JX45YGR* z{MO(o>;IxuK;jXw{QYv?(QKy5DnQcI^i8rr0f-_Xa709SPiZI-T3NlLL`1y2&yr;P z<24EO#@Nd}Ar=&9qeZHKMCTfI3j_6>00+7NnP#O^Osur5w||E))M=?n_&V*)lARnq zuwPpoZyWClEQix#QoOc-q(Xf$)85~Y&w0}q%NZ7CEy{q)xE-nyM5h;X6~Fi2rq5S4 zd8IC=7Y**36rYxb-Rw@jPnY>46VG7;S6Lkts1zimIES}fw*yKH&?M=n%_04Z1~;@7 z&Xo%+GOnWc?_Xlza~5)P_~<;N#sO-1iOBQLy)TAw^xyO{gJg~AY6q=Myho0l@fMW^ z{sryz?bSDHxN~g8z`!9WQRc1Owtl7A;#?9JJ=1+0tO^wh3Ngxs*AIeME#ZXf^B?|O zvITDHjg;FANT;{ACJNA;)3OO_AI;)ffr?#Hbh={L1hDbX5x3``wYPIFa)5cyJ)Dy` zOwE>k@tyt~qptn!^{Y8p4AM#a)?9VT#>F9y+s1VW*OJ^o0ymY+c9{NWf6a>A-dqU~ z`*`{^g2p0*;5{+1Z~rIHvU(O-7<};CgUpU`8veu98^^HN8#hTx>4+NIfZezZ^81SO z{X1Mdbhp7$n@a~cIgCV#xOcx>kAUyXMhMRoE=Ck zOA-`(NCxRsuXSkmNBc@Dgpv0sh4hL4`Jck)5HgciKV`KyN@K5lZD2#dL;~roXQ7bF zSYA#g^m+{Hg`eNyTG}tv_5X2c$V#o30|1FHZBx$cz=9Y>u)KkVG;DWVXXFU#qj$GO zriL!mp0i)EUm1}{uxOiRrR0~H;RMAIoCe>cKftgYt&~1|P=y^Q7`6rM>*Acf`jza7 zy57GN6&Kg?Wc)LHih>jZ{YU1eq&Ry8IXA)mvX%~7EPOqY`CXzOpM4h;d^_|ClW^T; ze@f7DgeW5Qpa=eaSkXL@Pi+;*>6JLl??1C+ zbv$K+5Kt)*>^_!>pDw};70HY2Rn;iLgsxI<~AY%Ka|y4ZFbvT0RSCbN|&E~lp5 z?>Vs8-Wl^an14ai%>qLAiGW0?=wyK=H&?ZCqlZNkBhU^f%dM26Su$5@H9?B#f@%Nk zs-a|fl7LKy`s2rAzMXx<^hVUPZ@H7D7m2!sxh@4!wrNf#dn0ZB>qQ*o`qq}!&o5(8J6 z__Np2+^!DpATG5~{|E?v&`+DLiKj(rNK^I~>g5?iO*JwkJ=|w#F}vXz9?%}GT5*3v zQ1vJ&t-B-T&1XSM;}K%{>U}cef!wd9-vT_(PoVJqSlbM4$cxdf4Bk65c6MAcKpha{ zY}>!U)8{gzPS5rTCvufB_AAtTQU+{ba-c=QNWs)C?B7m9!_E%5!BDtoQg}^5cEf2A zn{R|Dx@>o+KEaNOq~5^b#woG@mT&6UI9T-1BDoVCz`i#r0e_(f?&h8X!8iB!^$NiqBD<-1ib3f=+F;R)sx>kU#V8HtGD~mRwqFnqG zM*XV9zCbPAl{)lojcj^L;=pyn8HVxppOeOFEa#zPZ^^X+wj`3itT2y-jm zXPe87`t2shjcSw%RBx2APb`A{Gg#L>HR1pR z9mPC4kz0Zzd)JOd7>QmVN+@L@WRMRfg0Jm=&~gmGsW4UeJyj zJ%{+Zvu8`s6*FeX)GM>$M&v~I4;J~w$Fph?bq&9MCnv`WTOBI)k9;dDdxpo<)=LF) z6su(wuRvq9n5$m+*E4Ek|5Cl%g8$Sf6Qh5JxECjnjw^VX0}(P>Y;dl3eNyM)4wpwK z2hK91W~CEQ*?=m&T8j8zp0~M2TNzVcZej}{KeI_$t!nGXSF2%BI4ob_=G1@QNyV}3 zEtPZfu%QG?VsHF(vCporp9jI6rAk;};PKw>r^WhsB>#@->D#s5@+!023j^NkRFM5O z!YX+JLWqX~we}##F|Agn!+=SPmB|D(Rm1yr{Ofoyc7!HJPus@t%Pf0#ip8vP`A0=h zU=#2#U{x555O0ijzE_X?0y({34y5z*mQX zTt0!Cwgn9nzZ zD*y+H?5E{T3>7%OlT$Rn_{-)aTK(YcPn1405nkgSEX#?f%)SC{)& zll}NF0S6p%`evrb(e;p)6)9n zF=~>-8w|*$J9hRPvMZpQhjjgTl^A+-EjTu&2Kb;7VV82nr@t-@q9QtW&FV7_MGo>y z5~=H|!cS=_fBdWUTIqI~e_fus7rtj-AI+nTj02m7P76loKF~s1JHUg_pNRS&W%HAA z!Cz-5<~7K;-QKz`f{e_mlp&8T6~{{>d=`-HHT+dg8Of7L2QrU-GxihRn_G4{Kja(l zAB3_X==V}nAQm^hNWh2E>#Cl-gUHb39Wv1cZLv}%;LRk0w)OkuW9f8oM70A|u z_GVq>kq_Haf#HaXeA2(YO8oyC^a>7|Jnr0)NuEfvfT;feWn)30E`+z5ARt{H1*kJO z_p}HIyMnl4$pwk0d8dHY+*B)P0;iQ)JjcgmX4i{XPxFGXyLIxv^D33+xL%#1SS`4H zJ^ph{0crxs=>Gtt%*!{}yCdykdp;Hrw#fbPkD#Hjo2h{GL%Q7-IoOQ1mpgyp#(q-T z?cq4p^n7(XfQc?e3XAwV3?HdPzr4aN!9d-guMMQ(sEq_{21s(?Y^TxN0;l?HeCvzT z$b=Bg7y47XwlX;L`)9bEty~CD+hn)f<2Fil3YjCu{O*5_o?%d5%TW&h`GI(3qPUx<|NECG3bgg!(A`pAr-AIej<~SaF2E3y5k8ZJrkkCAUxtEjH>QI)JW+Uvj zWC`F(pn1B0;#nHY4KZr_szMD(B`8LtLyG$&2J3|z;|>Y9YpmWrjFjgGqaxq^s0g=E zd&%w2gX>rZ?DA@g#+$R3L9g#aAE`*MA?#(n z@&g#Lq^3w?Mm06HA&_z}Q3gNI{`BagVP$LtYH%`v53h3O8+=g? zi@2E-uR##8+!*WxTYR-)v7sI>0t5twbgixPmRoC|#ud>nSw0Mt$C@fj0f>JIwbUy; z0S>Ndbn^29GWWr)>9d2bE=;5hoQ@?2gbW)w5I02V193y^)ncsaRv55?K&rK1<;c7C z(^_e}fV@`;eT>uHt%nMA^LCxjH8(M8BFJ`1eZ4f;05R4AjZF7*qT2rC#g}AcnAuwC zet1`r#8Rpdj!-!E?FCtcBu}O#l)RSe2e=lHi?S8^%(TXVlI<@3@v*w)LSiHTHlnJZpMxjlMkE+S;1S@4Eh(yxf7;!|hd_19%axVDKT;T*D3`lboCI zeuB4i#BAhl#8vuRMzx3-Ev(Ld$3mlGbI}X;649 zB))78&?7T3t8^2~e!Dkes_`Hl1twvU7lbw|m_hV`d3hAlKJ3c*YS0MZXA*2?Dqmkd z^b3S%^gM=+@ME*E`qBkocH+r!*!xY`NM-az_Rw~*ITXB9j*ZWS8UPTdU=gk`bjtmD z7Y$pqm`m|E%8+@FjFx2bb#$xzp|U#_>4x?kW3d?~zIcE8|H>WR8%~`dfH9W?crOT?ZaByOJXg0_5R#!Vt9UL9o+woa4ST!yN1rHu2 zAS_seohbVX(UTXf?pV6Nr?oY`EDQt_zrRXlE+nkX)mikP$DX4FtbsvrB9!11BX~7e zzpB*#YZ3v|so)*aui%_aP%oIZ0`L^knNzDHe>ZDiQ>><(-_N{lWhRqY5UJ=`>=TaX zT1f8V>p((=)E~rWDw^n8ePGw+d%?p7Z(dEwu`bY@l$Md{&Ohe)2Spk;9#WR|D$oQ# zjLa~LjACerGlH4$Lm`){G0Pxw(;OHvkH%{2i+m|LcV{GOc(sjje{VoI@8QwY+1Eiv zBBGCkkGMmeDE9ke)i^m#xB?i^WwhH&Sw(+j7Pju4fX#+8yuPLpnNi0SPBm-@f4tnpBw0ikI zQV?lP{7yq@JN@bOI*C^-h3obf=kfVdABs%UkIgA5DaO(K(1)CWe2kSC7>L6V ztWFfGPXi974k5Fmd=1iXVD~QpFdSB)i-Ye9D9q;c!2K4sdAaPr9!&}GhUesK4vqvG zNjl{^jBop0bs%?pwl%8Jb@_u;2xjg-1jYjOJP?bB%AwiIZW2$%a~7tgidGDd(WckL z(&=TCzt%@2oO?>Gdv#WRz_0@+vRtQ2CG|4bVZT2Wavzknva4c$TCw!{A>rDuu~}-N zYuSEA@BIVDBoJ|1DdG9xAaIdFQzz8c8%68!dr7|`*YmFOx14&NE{xO3f2HMfB621v z5kI&qbU3`aN+D!46_{UC2ZCF-anrz8MsNw#R#S(Lj5bGyKGTomu}^9Aw7``ZeS9WD zObd~E=7%)1caQ&x=WGsFBC^V5_>&>?0SVNZq(aR5UH7QQ7)=!$uRy zMR*im&69lw_tB<>TJw{5L}K7_Hp2-e#=aqe$WNdC@-$D^CVWNO|1eVot(^kZhT%I5 zq}N(n;9XecPjjr9#aULE?X7zvLMAPOUU73a`r+h9LFC=*9vR%6nftG0Qw zH6k{}OVKr5mM!S!c*fue#vWjTz$rjgcrsb=%>TzH{pm6jRINS~LMjk1oG%6H^LW~% zK8jYd*8+#lYO%Rvx|bHDNrj%ZQsIQ3Mtfe;q6%F8IkpKv!yn=1t4qefrrcTDP9xoY zz(_ok3BU`8JASS|qq;v8kNazzb;ZiN@3GdK*}kr7();*cby+oSlZH4f2e}$gvYFBE z+r_4QWXc0UE&K$5BO=~Ptsy=MaEqhb1sFGm*pCT*s1y)g;>j_&a1!l+_`DG`lAq|; z{(jHK$dY}Ee!IfYPtz@{VqViacW~ntG|IG^Z7CSs?`DcNy(*3QnUoPSBxHt{`TSSR zLa;Xm2IcCLsO+xr7qmHikI_GUD%}`#F16c6R)@j~I14)nWH_iWD{?{WGgsaikcnX? zq31mb$3vj`&YXPwO=rNT3=&WFE`Ty83?8+oF&%fIVHxPSzdO49Ww{+DlH`Y2;F>EWTf=4#LFRSXW(@d=IA^c<%E|DRa4>-QM)=rhE|+MqCfL zT91z|);hT|w`qniTXPPViGZtwWP*#-b2`sGK=yWX1&@h{OyCk+NCkrDH@Jz_?A$by zDJ|ix2Hw?nrLaNA$z!?{_9kYopqqZ?9eN6W5T)yRGy}VG0B{hzr7rI38X6?HsKT>=E@ZOrmVY?A^zq^cncG@Kxg3BWlX>OA3Wr7x18h}EsLQ9ln(8I5A|bCVJ*M> zcpecv$m!hJ|3e08P z3U&!?-o7f-`f0xWzR6=bxY+STyH`-CEtNhazvT2WDv<&!8V=0x%&cbXc-N&Ghz3xvNE zSRoN|c@MgO8#gyuTRQH=S)7soknxk3n^Lu{X+xR)WIC-WW`Gg6!q=l{*cFPcMEnpb z*>8~g`?#XXW*VtzN5~GNK)=HtL0h}bbfty3kkHIx$KRg|7y_ZKCCcCok=}2dK=?_C znUUFuKU}xqKH|a_-rAAN!p&8OhJ_pd(;QJ9OOg19o|i1FFwi}Nx?Qxg2=N|rhUb|w z#db7{nQ=H-OOzX%n|}NOCd)!X&ND!rY?fOvb`Jz2W02EHXQgfxBeUM}a_xnn%CwSW zwmV1Z1V@4Gem!*##I~FG-F=b5gV^s(m`|6MtgPxEGihJfI9dVMqB_N3lZ?3u4r%>U z0s!vYBy=e`EXbC@WY0tf8U*F}5ED&KY>HO`Fz`#;7CoeeDuIpA_U~`v>wcSn2KIkE zv|*dF7`2&5bJ|18*lzPta6dBYwDffVJZNx#gwsQ9Ds-42q=gwbf@UE7Ev%FRGV1<^ z-ReE{87XgG_P~%BOt-+QL5gs?qf=DC!!757{5k0BWe*(wE-Sd!3k6m~gPk%UcIS0O46(|s-~cMMW6y*|9%`g8-qKbJO1RmcAced3G5Zm`JR(p@E}WJAaLF5&;;C^U-UyOPazv|W=`bR;~n zK;v{N$eEf30SQVNK}C#(k3Duj`dqi&m;A!z7GDbBvHBg4RhTIr`AEX!Xe3E$Cz9dc zUlQ|HCfvCru@7qwu)z=4no$Tw6YTTe7

    $0ITcj(KRIbdLxc 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 diff --git a/caching/etc/caching.ucls b/caching/etc/caching.ucls index 815a62ec9..a058277ea 100644 --- a/caching/etc/caching.ucls +++ b/caching/etc/caching.ucls @@ -1,106 +1,90 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/caching/src/main/java/com/iluwatar/caching/App.java b/caching/src/main/java/com/iluwatar/caching/App.java index 4a3a9ab42..1b1b5e1ca 100644 --- a/caching/src/main/java/com/iluwatar/caching/App.java +++ b/caching/src/main/java/com/iluwatar/caching/App.java @@ -26,22 +26,23 @@ package com.iluwatar.caching; * * The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing * the resources immediately after their use. The resources retain their identity, are kept in some - * fast-access storage, and are re-used to avoid having to acquire them again. There are three main - * caching strategies/techniques in this pattern; each with their own pros and cons. They are: + * fast-access storage, and are re-used to avoid having to acquire them again. There are four main + * caching strategies/techniques in this pattern; each with their own pros and cons. They are; * write-through which writes data to the cache and DB in a single transaction, - * write-around which writes data immediately into the DB instead of the cache, and + * write-around which writes data immediately into the DB instead of the cache, * write-behind which writes data into the cache initially whilst the data is only - * written into the DB when the cache is full. The read-through strategy is also - * included in the mentioned three strategies -- returns data from the cache to the caller if - * it exists else queries from DB and stores it into the cache for future use. These - * strategies determine when the data in the cache should be written back to the backing store (i.e. - * Database) and help keep both data sources synchronized/up-to-date. This pattern can improve - * performance and also helps to maintain consistency between data held in the cache and the data in - * the underlying data store. + * written into the DB when the cache is full, and cache-aside which pushes the + * responsibility of keeping the data synchronized in both data sources to the application itself. + * The read-through strategy is also included in the mentioned four strategies -- + * returns data from the cache to the caller if it exists else queries from DB and + * stores it into the cache for future use. These strategies determine when the data in the cache + * should be written back to the backing store (i.e. Database) and help keep both data sources + * synchronized/up-to-date. This pattern can improve performance and also helps to maintain + * consistency between data held in the cache and the data in the underlying data store. *

    * In this example, the user account ({@link UserAccount}) entity is used as the underlying * application data. The cache itself is implemented as an internal (Java) data structure. It adopts - * a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The three + * a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The four * strategies are individually tested. The testing of the cache is restricted towards saving and * querying of user accounts from the underlying data store ( {@link DbManager}). The main class ( * {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and diff --git a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java index 0c907fe88..5ad32f699 100644 --- a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java +++ b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java @@ -24,7 +24,7 @@ package com.iluwatar.caching; /** * - * Enum class containing the three caching strategies implemented in the pattern. + * Enum class containing the four caching strategies implemented in the pattern. * */ public enum CachingPolicy { diff --git a/caching/src/main/java/com/iluwatar/caching/LruCache.java b/caching/src/main/java/com/iluwatar/caching/LruCache.java index 4527b5548..00e27ccf1 100644 --- a/caching/src/main/java/com/iluwatar/caching/LruCache.java +++ b/caching/src/main/java/com/iluwatar/caching/LruCache.java @@ -73,7 +73,6 @@ public class LruCache { } /** - * * Remove node from linked list. */ public void remove(Node node) { @@ -90,7 +89,6 @@ public class LruCache { } /** - * * Move node to the front of the list. */ public void setHead(Node node) { @@ -161,7 +159,6 @@ public class LruCache { } /** - * * Returns cache data in list form. */ public List getCacheDataInListForm() { diff --git a/caching/src/main/java/com/iluwatar/caching/UserAccount.java b/caching/src/main/java/com/iluwatar/caching/UserAccount.java index e2444ad72..657f12fa3 100644 --- a/caching/src/main/java/com/iluwatar/caching/UserAccount.java +++ b/caching/src/main/java/com/iluwatar/caching/UserAccount.java @@ -23,9 +23,7 @@ package com.iluwatar.caching; /** - * * Entity class (stored in cache and DB) used in the application. - * */ public class UserAccount { private String userId; From 85060784a7758af064aa883d66f029dd292ea9e8 Mon Sep 17 00:00:00 2001 From: dzmitryh Date: Sat, 15 Oct 2016 14:27:15 +0300 Subject: [PATCH 083/492] End process logic clause has been corrected. --- .../async/method/invocation/ThreadAsyncExecutor.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java index 7f96d9ab7..5a10232f0 100644 --- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java +++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java @@ -57,12 +57,10 @@ public class ThreadAsyncExecutor implements AsyncExecutor { @Override public T endProcess(AsyncResult asyncResult) throws ExecutionException, InterruptedException { - if (asyncResult.isCompleted()) { - return asyncResult.getValue(); - } else { + if (!asyncResult.isCompleted()) { asyncResult.await(); - return asyncResult.getValue(); } + return asyncResult.getValue(); } /** From 37b930c3b75ebc17ac46f6ce9f93ef1ed8435aeb Mon Sep 17 00:00:00 2001 From: dzmitryh Date: Sat, 15 Oct 2016 14:29:32 +0300 Subject: [PATCH 084/492] Unused import removed. --- .../async/method/invocation/ThreadAsyncExecutorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java index b4a23222a..09126e99f 100644 --- a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java +++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java @@ -31,7 +31,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import static org.junit.Assert.*; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; import static org.mockito.internal.verification.VerificationModeFactory.times; From 986c529eb67e5eccd999e4bc13d268a8c5997fc7 Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 17 Oct 2016 21:29:03 +0100 Subject: [PATCH 085/492] Moved config into a separate dir --- event-asynchronous/src/main/java/config.properties | 1 - event-asynchronous/src/main/resources/config.properties | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 event-asynchronous/src/main/java/config.properties create mode 100644 event-asynchronous/src/main/resources/config.properties diff --git a/event-asynchronous/src/main/java/config.properties b/event-asynchronous/src/main/java/config.properties deleted file mode 100644 index edbe90e05..000000000 --- a/event-asynchronous/src/main/java/config.properties +++ /dev/null @@ -1 +0,0 @@ -INTERACTIVE_MODE=NO \ No newline at end of file diff --git a/event-asynchronous/src/main/resources/config.properties b/event-asynchronous/src/main/resources/config.properties new file mode 100644 index 000000000..7216f665d --- /dev/null +++ b/event-asynchronous/src/main/resources/config.properties @@ -0,0 +1 @@ +INTERACTIVE_MODE=YES \ No newline at end of file From 70318123fe762d919eda221e08b0f7bf2db5b8dd Mon Sep 17 00:00:00 2001 From: WSSIA Date: Mon, 17 Oct 2016 22:22:06 +0100 Subject: [PATCH 086/492] Changed config to non-interactive --- event-asynchronous/src/main/resources/config.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event-asynchronous/src/main/resources/config.properties b/event-asynchronous/src/main/resources/config.properties index 7216f665d..edbe90e05 100644 --- a/event-asynchronous/src/main/resources/config.properties +++ b/event-asynchronous/src/main/resources/config.properties @@ -1 +1 @@ -INTERACTIVE_MODE=YES \ No newline at end of file +INTERACTIVE_MODE=NO \ No newline at end of file From 99677867c66a318f4f41e714a7ed867131cfcdd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 18 Oct 2016 07:51:37 +0300 Subject: [PATCH 087/492] Event Based Asynchronous pattern: Add missing license header and puml diagram --- .../etc/event-asynchronous.urm.puml | 65 +++++++++++++++++++ .../src/main/resources/config.properties | 23 +++++++ 2 files changed, 88 insertions(+) create mode 100644 event-asynchronous/etc/event-asynchronous.urm.puml diff --git a/event-asynchronous/etc/event-asynchronous.urm.puml b/event-asynchronous/etc/event-asynchronous.urm.puml new file mode 100644 index 000000000..c5b183187 --- /dev/null +++ b/event-asynchronous/etc/event-asynchronous.urm.puml @@ -0,0 +1,65 @@ +@startuml +package com.iluwatar.event.asynchronous { + class Event { + - eventId : int + - eventListener : ThreadCompleteListener + - eventTime : int + - isComplete : boolean + - isSynchronous : boolean + - thread : Thread + + Event(eventId : int, eventTime : int, isSynchronous : boolean) + + addListener(listener : ThreadCompleteListener) + - completed() + + isSynchronous() : boolean + + removeListener(listener : ThreadCompleteListener) + + run() + + start() + + status() + + stop() + } + interface ThreadCompleteListener { + + completedEventHandler(int) {abstract} + } + class EventManager { + + MAX_EVENT_TIME : int {static} + + MAX_ID : int {static} + + MAX_RUNNING_EVENTS : int {static} + + MIN_ID : int {static} + - currentlyRunningSyncEvent : int + - eventPool : Map + - rand : Random + + EventManager() + + cancel(eventId : int) + + completedEventHandler(eventId : int) + + create(eventTime : int) : int + + createAsync(eventTime : int) : int + - createEvent(eventTime : int, isSynchronous : boolean) : int + - generateId() : int + + getEventPool() : Map + + numOfCurrentlyRunningSyncEvent() : int + + shutdown() + + start(eventId : int) + + status(eventId : int) + + statusOfAllEvents() + } + class App { + + PROP_FILE_NAME : String {static} + ~ interactiveMode : boolean + + App() + + main(args : String[]) {static} + + quickRun() + + run() + + runInteractiveMode() + + setUp() + } + interface IEvent { + + start() {abstract} + + status() {abstract} + + stop() {abstract} + } +} +Event --> "-eventListener" ThreadCompleteListener +EventManager --+ Map +Event ..|> IEvent +EventManager ..|> ThreadCompleteListener +@enduml \ No newline at end of file diff --git a/event-asynchronous/src/main/resources/config.properties b/event-asynchronous/src/main/resources/config.properties index edbe90e05..d8bfa1f7e 100644 --- a/event-asynchronous/src/main/resources/config.properties +++ b/event-asynchronous/src/main/resources/config.properties @@ -1 +1,24 @@ +# +# The MIT License +# Copyright (c) 2014 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. +# + INTERACTIVE_MODE=NO \ No newline at end of file From b66e8ecef970858e7823e6319ac378ba7fadfaea Mon Sep 17 00:00:00 2001 From: Dmitry Avershin Date: Tue, 18 Oct 2016 14:18:47 +0200 Subject: [PATCH 088/492] Adds more criticism to Singleton pattern. --- service-locator/README.md | 1 - singleton/README.md | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/service-locator/README.md b/service-locator/README.md index 75a00ca57..479c9ed0f 100644 --- a/service-locator/README.md +++ b/service-locator/README.md @@ -38,7 +38,6 @@ improves the performance of application to great extent. * Violates Interface Segregation Principle (ISP) by providing pattern consumers with an access to a number of services that they don't potentially need. * Creates hidden dependencies that can break the clients at runtime. -* Limits object composability by stopping the clients to specify needed dependencies for different objects instantiation. ## Credits diff --git a/singleton/README.md b/singleton/README.md index 38a05349b..4032ffaed 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -40,6 +40,8 @@ Use the Singleton pattern when * Violates Single Responsibility Principle (SRP) by controlling their own creation and lifecycle. * Encourages using a global shared instance which prevents an object and resources used by this object from being deallocated. +* Creates tightly coupled code that is difficult to test. +* Makes it almost impossible to subclass a Singleton. ## Credits From ffdaf2ec4717164f466294bd7c37427fe3cddcdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 19 Oct 2016 22:25:37 +0300 Subject: [PATCH 089/492] Add Travis instructions for SonarQube.com analysis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 613f737d7..4cfffe701 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ env: global: - GH_REF: github.com/iluwatar/java-design-patterns.git - secure: LxTDuNS/rBWIvKkaEqr79ImZAe48mCdoYCF41coxNXgNoippo4GIBArknqtv+XvdkiuRZ1yGyj6pn8GU33c/yn+krddTUkVCwTbVatbalW5jhQjDbHYym/JcxaK9ZS/3JTeGcWrBgiPqHEEDhCf26vPZsXoMSeVCEORVKTp1BSg= + - secure: "eoWlW9GyTJY04P8K3pxayXwU9/hmptQg/LfirispQkV9YvmziCfSzXnatnBhNfud98sCzY8BScXnb+OWLTnjLKpId4rtEqb0aJ40Jc32cUKzgzFAUn7cNcDAbUIfyPAGVqyQqfj/11wYSADwWMMOPlW97ExUtoyiH2WenXuRHso=" before_install: - export DISPLAY=:99.0 @@ -17,6 +18,7 @@ install: after_success: - mvn clean test jacoco:report coveralls:report +- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=SONAR_TOKEN - bash update-ghpages.sh # use latest java version available instead of travis default From 19cb715d20f269eb00aa6569244bf090459eb6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 19 Oct 2016 23:08:51 +0300 Subject: [PATCH 090/492] Fix environment variable --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4cfffe701..ba226ff5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ install: after_success: - mvn clean test jacoco:report coveralls:report -- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=SONAR_TOKEN +- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=$SONAR_TOKEN - bash update-ghpages.sh # use latest java version available instead of travis default From 1c0278592703a20720bb00b7490d435819afffb2 Mon Sep 17 00:00:00 2001 From: Fabrice Bellingard Date: Sun, 23 Oct 2016 14:35:45 +0200 Subject: [PATCH 091/492] Add SonarQube.com badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1789398ec..214fa91ff 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ [![Coverage Status](https://coveralls.io/repos/iluwatar/java-design-patterns/badge.svg?branch=master)](https://coveralls.io/r/iluwatar/java-design-patterns?branch=master) [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Quality Gate](https://sonarqube.com/api/badges/gate?key=com.iluwatar%3Ajava-design-patterns)](https://sonarqube.com/dashboard/index/com.iluwatar%3Ajava-design-patterns) # Introduction From 0438811489c16948ad8418e9a3ce59bc10bd92c6 Mon Sep 17 00:00:00 2001 From: daniel-bryla Date: Sun, 23 Oct 2016 19:59:03 +0200 Subject: [PATCH 092/492] #502 Replaced usages of System.out with logger. --- .../com/iluwatar/abstractdocument/App.java | 17 +- .../com/iluwatar/abstractfactory/App.java | 21 +- .../iluwatar/adapter/BattleFishingBoat.java | 7 +- .../com/iluwatar/adapter/FishingBoat.java | 9 +- .../ProductInformationClientImpl.java | 6 +- .../ProductInventoryClientImpl.java | 6 +- .../iluwatar/async/method/invocation/App.java | 7 +- .../java/com/iluwatar/bridge/Excalibur.java | 13 +- .../java/com/iluwatar/bridge/Mjollnir.java | 13 +- .../com/iluwatar/bridge/Stormbringer.java | 13 +- .../main/java/com/iluwatar/builder/App.java | 10 +- .../business/delegate/EjbService.java | 7 +- .../business/delegate/JmsService.java | 7 +- .../main/java/com/iluwatar/caching/App.java | 30 +-- .../java/com/iluwatar/caching/CacheStore.java | 19 +- .../java/com/iluwatar/caching/LruCache.java | 9 +- .../main/java/com/iluwatar/callback/App.java | 7 +- .../com/iluwatar/callback/LambdasApp.java | 7 +- .../com/iluwatar/callback/SimpleTask.java | 7 +- .../com/iluwatar/chain/RequestHandler.java | 7 +- .../java/com/iluwatar/command/Target.java | 9 +- .../java/com/iluwatar/command/Wizard.java | 11 +- .../main/java/com/iluwatar/composite/App.java | 11 +- .../java/com/iluwatar/composite/Letter.java | 7 +- .../java/com/iluwatar/composite/Sentence.java | 7 +- .../java/com/iluwatar/composite/Word.java | 7 +- .../main/java/com/iluwatar/decorator/App.java | 13 +- .../com/iluwatar/decorator/SmartHostile.java | 9 +- .../java/com/iluwatar/decorator/Troll.java | 9 +- .../simple/printers/CanonPrinter.java | 6 +- .../simple/printers/EpsonPrinter.java | 6 +- .../delegation/simple/printers/HpPrinter.java | 6 +- .../dependency/injection/Tobacco.java | 9 +- .../iluwatar/doublechecked/locking/App.java | 7 +- .../doublechecked/locking/Inventory.java | 8 +- .../java/com/iluwatar/doubledispatch/App.java | 15 +- .../iluwatar/doubledispatch/Meteoroid.java | 17 +- .../doubledispatch/SpaceStationMir.java | 22 ++- .../event/aggregator/KingJoffrey.java | 7 +- .../eda/handler/UserCreatedEventHandler.java | 8 +- .../eda/handler/UserUpdatedEventHandler.java | 8 +- .../iluwatar/facade/DwarvenCartOperator.java | 7 +- .../iluwatar/facade/DwarvenGoldDigger.java | 7 +- .../iluwatar/facade/DwarvenMineWorker.java | 15 +- .../iluwatar/facade/DwarvenTunnelDigger.java | 7 +- .../java/com/iluwatar/factorykit/App.java | 8 +- .../java/com/iluwatar/factory/method/App.java | 9 +- .../java/com/iluwatar/featuretoggle/App.java | 12 +- .../com/iluwatar/fluentinterface/app/App.java | 14 +- .../com/iluwatar/flux/view/ContentView.java | 6 +- .../java/com/iluwatar/flux/view/MenuView.java | 8 +- .../com/iluwatar/flyweight/AlchemistShop.java | 9 +- .../com/iluwatar/flyweight/HealingPotion.java | 7 +- .../iluwatar/flyweight/HolyWaterPotion.java | 7 +- .../flyweight/InvisibilityPotion.java | 7 +- .../com/iluwatar/flyweight/PoisonPotion.java | 7 +- .../iluwatar/flyweight/StrengthPotion.java | 7 +- .../iluwatar/front/controller/ArcherView.java | 7 +- .../front/controller/CatapultView.java | 7 +- .../iluwatar/front/controller/ErrorView.java | 7 +- .../com/iluwatar/halfsynchalfasync/App.java | 9 +- .../administration/ConsoleAdministration.java | 26 +-- .../hexagonal/eventlog/StdOutEventLog.java | 26 +-- .../hexagonal/service/ConsoleLottery.java | 56 +++--- .../java/com/iluwatar/interpreter/App.java | 17 +- .../main/java/com/iluwatar/iterator/App.java | 19 +- .../com/iluwatar/layers/CakeViewImpl.java | 7 +- .../java/com/iluwatar/layers/StdOutTest.java | 2 + .../java/com/iluwatar/lazy/loading/App.java | 12 +- .../java/com/iluwatar/lazy/loading/Heavy.java | 11 +- .../iluwatar/lazy/loading/HolderNaive.java | 7 +- .../lazy/loading/HolderThreadSafe.java | 7 +- .../iluwatar/lazy/loading/Java8Holder.java | 7 +- .../iluwatar/mediator/PartyMemberBase.java | 11 +- .../main/java/com/iluwatar/memento/App.java | 17 +- .../com/iluwatar/message/channel/App.java | 6 +- .../model/view/controller/GiantView.java | 7 +- .../src/main/java/com/iluwatar/monad/App.java | 7 +- .../java/com/iluwatar/monostate/Server.java | 10 +- .../main/java/com/iluwatar/multiton/App.java | 23 ++- .../src/main/java/com/iluwatar/mute/App.java | 7 +- .../test/java/com/iluwatar/mute/MuteTest.java | 6 +- .../main/java/com/iluwatar/mutex/Thief.java | 9 +- naked-objects/dom/log4j.properties | 41 ---- naked-objects/integtests/logging.properties | 111 ----------- .../main/webapp/WEB-INF/logging.properties | 187 ------------------ .../com/iluwatar/nullobject/NodeImpl.java | 7 +- .../java/com/iluwatar/object/pool/App.java | 29 +-- .../main/java/com/iluwatar/observer/App.java | 6 +- .../java/com/iluwatar/observer/Hobbits.java | 13 +- .../main/java/com/iluwatar/observer/Orcs.java | 13 +- .../java/com/iluwatar/observer/Weather.java | 7 +- .../iluwatar/observer/generic/GHobbits.java | 13 +- .../com/iluwatar/observer/generic/GOrcs.java | 12 +- .../iluwatar/observer/generic/GWeather.java | 6 +- .../com/iluwatar/poison/pill/Consumer.java | 11 +- .../com/iluwatar/poison/pill/Producer.java | 8 +- pom.xml | 25 ++- .../privateclassdata/ImmutableStew.java | 10 +- .../com/iluwatar/privateclassdata/Stew.java | 12 +- .../com/iluwatar/producer/consumer/App.java | 7 +- .../iluwatar/producer/consumer/Consumer.java | 8 +- .../main/java/com/iluwatar/promise/App.java | 9 +- .../java/com/iluwatar/promise/Utility.java | 9 +- .../main/java/com/iluwatar/property/App.java | 12 +- .../main/java/com/iluwatar/prototype/App.java | 17 +- .../java/com/iluwatar/proxy/WizardTower.java | 7 +- .../com/iluwatar/proxy/WizardTowerProxy.java | 7 +- .../com/iluwatar/publish/subscribe/App.java | 6 +- .../com/iluwatar/reactor/app/AppClient.java | 14 +- .../iluwatar/reactor/app/LoggingHandler.java | 6 +- .../reactor/framework/NioDatagramChannel.java | 7 +- .../reactor/framework/NioReactor.java | 7 +- .../framework/NioServerSocketChannel.java | 7 +- .../com/iluwatar/reader/writer/lock/App.java | 7 +- .../iluwatar/reader/writer/lock/Reader.java | 9 +- .../iluwatar/reader/writer/lock/Writer.java | 9 +- .../writer/lock/ReaderAndWriterTest.java | 8 +- .../reader/writer/lock/ReaderTest.java | 6 +- .../reader/writer/lock/WriterTest.java | 6 +- .../java/com/iluwatar/repository/App.java | 18 +- .../com/iluwatar/repository/AppConfig.java | 18 +- .../acquisition/is/initialization/App.java | 9 +- .../is/initialization/SlidingDoor.java | 9 +- .../is/initialization/TreasureChest.java | 9 +- .../java/com/iluwatar/semaphore/Customer.java | 11 +- .../main/java/com/iluwatar/servant/App.java | 9 +- .../com/iluwatar/servicelayer/app/App.java | 24 ++- .../servicelayer/hibernate/HibernateUtil.java | 6 +- .../iluwatar/servicelocator/InitContext.java | 9 +- .../iluwatar/servicelocator/ServiceCache.java | 9 +- .../iluwatar/servicelocator/ServiceImpl.java | 7 +- .../main/java/com/iluwatar/singleton/App.java | 25 ++- .../com/iluwatar/specification/app/App.java | 16 +- .../java/com/iluwatar/state/AngryState.java | 9 +- .../com/iluwatar/state/PeacefulState.java | 9 +- .../java/com/iluwatar/stepbuilder/App.java | 11 +- .../main/java/com/iluwatar/strategy/App.java | 23 ++- .../com/iluwatar/strategy/MeleeStrategy.java | 7 +- .../iluwatar/strategy/ProjectileStrategy.java | 8 +- .../com/iluwatar/strategy/SpellStrategy.java | 8 +- .../templatemethod/HitAndRunMethod.java | 9 +- .../templatemethod/StealingMethod.java | 7 +- .../iluwatar/templatemethod/SubtleMethod.java | 9 +- .../java/com/iluwatar/threadpool/App.java | 9 +- .../java/com/iluwatar/threadpool/Worker.java | 8 +- .../java/com/iluwatar/tolerantreader/App.java | 23 ++- .../main/java/com/iluwatar/twin/BallItem.java | 9 +- .../java/com/iluwatar/twin/BallThread.java | 9 +- .../main/java/com/iluwatar/twin/GameItem.java | 7 +- .../java/com/iluwatar/value/object/App.java | 12 +- .../iluwatar/visitor/CommanderVisitor.java | 7 +- .../com/iluwatar/visitor/SergeantVisitor.java | 7 +- .../com/iluwatar/visitor/SoldierVisitor.java | 7 +- 154 files changed, 1155 insertions(+), 792 deletions(-) delete mode 100644 naked-objects/dom/log4j.properties delete mode 100644 naked-objects/integtests/logging.properties delete mode 100644 naked-objects/webapp/src/main/webapp/WEB-INF/logging.properties diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java index d7758b6f7..35cdf7625 100644 --- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java +++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java @@ -27,6 +27,8 @@ import com.iluwatar.abstractdocument.domain.HasModel; import com.iluwatar.abstractdocument.domain.HasParts; import com.iluwatar.abstractdocument.domain.HasPrice; import com.iluwatar.abstractdocument.domain.HasType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.HashMap; @@ -44,11 +46,13 @@ import java.util.Map; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Executes the App */ public App() { - System.out.println("Constructing parts and car"); + LOGGER.info("Constructing parts and car"); Map carProperties = new HashMap<>(); carProperties.put(HasModel.PROPERTY, "300SL"); @@ -68,12 +72,11 @@ public class App { Car car = new Car(carProperties); - System.out.println("Here is our car:"); - System.out.println("-> model: " + car.getModel().get()); - System.out.println("-> price: " + car.getPrice().get()); - System.out.println("-> parts: "); - car.getParts().forEach(p -> System.out - .println("\t" + p.getType().get() + "/" + p.getModel().get() + "/" + p.getPrice().get())); + LOGGER.info("Here is our car:"); + LOGGER.info("-> model: {}", car.getModel().get()); + LOGGER.info("-> price: {}", car.getPrice().get()); + LOGGER.info("-> parts: "); + car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}", p.getType().get(), p.getModel().get(), p.getPrice().get())); } /** diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java index aae396f1d..abc75a951 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.abstractfactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme @@ -39,6 +42,8 @@ package com.iluwatar.abstractfactory; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private King king; private Castle castle; private Army army; @@ -98,17 +103,17 @@ public class App { App app = new App(); - System.out.println("Elf Kingdom"); + LOGGER.info("Elf Kingdom"); app.createKingdom(new ElfKingdomFactory()); - System.out.println(app.getArmy().getDescription()); - System.out.println(app.getCastle().getDescription()); - System.out.println(app.getKing().getDescription()); + LOGGER.info(app.getArmy().getDescription()); + LOGGER.info(app.getCastle().getDescription()); + LOGGER.info(app.getKing().getDescription()); - System.out.println("\nOrc Kingdom"); + LOGGER.info("Orc Kingdom"); app.createKingdom(new OrcKingdomFactory()); - System.out.println(app.getArmy().getDescription()); - System.out.println(app.getCastle().getDescription()); - System.out.println(app.getKing().getDescription()); + LOGGER.info(app.getArmy().getDescription()); + LOGGER.info(app.getCastle().getDescription()); + LOGGER.info(app.getKing().getDescription()); } diff --git a/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java index a591818fe..265f127c4 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java +++ b/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java @@ -22,6 +22,9 @@ */ package com.iluwatar.adapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link BattleShip} @@ -33,6 +36,8 @@ package com.iluwatar.adapter; */ public class BattleFishingBoat implements BattleShip { + private static final Logger LOGGER = LoggerFactory.getLogger(BattleFishingBoat.class); + private FishingBoat boat; public BattleFishingBoat() { @@ -41,7 +46,7 @@ public class BattleFishingBoat implements BattleShip { @Override public void fire() { - System.out.println("fire!"); + LOGGER.info("fire!"); } @Override diff --git a/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java index 307437038..a10e90967 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java +++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java @@ -22,6 +22,9 @@ */ package com.iluwatar.adapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Device class (adaptee in the pattern). We want to reuse this class @@ -29,12 +32,14 @@ package com.iluwatar.adapter; */ public class FishingBoat { + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class); + public void sail() { - System.out.println("The Boat is moving to that place"); + LOGGER.info("The Boat is moving to that place"); } public void fish() { - System.out.println("fishing ..."); + LOGGER.info("fishing ..."); } } diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java index 1c5c1527c..e86a84563 100644 --- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java +++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java @@ -27,6 +27,8 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.io.IOException; @@ -37,6 +39,8 @@ import java.io.IOException; @Component public class ProductInformationClientImpl implements ProductInformationClient { + private static final Logger LOGGER = LoggerFactory.getLogger(ProductInformationClientImpl.class); + @Override public String getProductTitle() { String response = null; @@ -46,7 +50,7 @@ public class ProductInformationClientImpl implements ProductInformationClient { response = EntityUtils.toString(httpResponse.getEntity()); } } catch (IOException e) { - e.printStackTrace(); + LOGGER.error("Exception caught.", e); } return response; } diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java index 14d0a32c4..c736462e6 100644 --- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java +++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java @@ -27,6 +27,8 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.io.IOException; @@ -37,6 +39,8 @@ import java.io.IOException; @Component public class ProductInventoryClientImpl implements ProductInventoryClient { + private static final Logger LOGGER = LoggerFactory.getLogger(ProductInventoryClientImpl.class); + @Override public int getProductInventories() { String response = "0"; @@ -46,7 +50,7 @@ public class ProductInventoryClientImpl implements ProductInventoryClient { response = EntityUtils.toString(httpResponse.getEntity()); } } catch (IOException e) { - e.printStackTrace(); + LOGGER.error("Exception caught.", e); } return Integer.parseInt(response); } diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java index 0a56dc166..ee33ea1db 100644 --- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java +++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.async.method.invocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.Callable; /** @@ -54,6 +57,8 @@ import java.util.concurrent.Callable; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ @@ -120,6 +125,6 @@ public class App { } private static void log(String msg) { - System.out.println(String.format("[%1$-10s] - %2$s", Thread.currentThread().getName(), msg)); + LOGGER.info(msg); } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java b/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java index 2523b3557..28bcf13fa 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java @@ -22,6 +22,9 @@ */ package com.iluwatar.bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Excalibur @@ -29,23 +32,25 @@ package com.iluwatar.bridge; */ public class Excalibur extends BlindingMagicWeaponImpl { + private static final Logger LOGGER = LoggerFactory.getLogger(Excalibur.class); + @Override public void wieldImp() { - System.out.println("wielding Excalibur"); + LOGGER.info("wielding Excalibur"); } @Override public void swingImp() { - System.out.println("swinging Excalibur"); + LOGGER.info("swinging Excalibur"); } @Override public void unwieldImp() { - System.out.println("unwielding Excalibur"); + LOGGER.info("unwielding Excalibur"); } @Override public void blindImp() { - System.out.println("bright light streams from Excalibur blinding the enemy"); + LOGGER.info("bright light streams from Excalibur blinding the enemy"); } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java b/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java index 0cc31b471..a57d75abc 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java @@ -22,6 +22,9 @@ */ package com.iluwatar.bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Mjollnir @@ -29,23 +32,25 @@ package com.iluwatar.bridge; */ public class Mjollnir extends FlyingMagicWeaponImpl { + private static final Logger LOGGER = LoggerFactory.getLogger(Mjollnir.class); + @Override public void wieldImp() { - System.out.println("wielding Mjollnir"); + LOGGER.info("wielding Mjollnir"); } @Override public void swingImp() { - System.out.println("swinging Mjollnir"); + LOGGER.info("swinging Mjollnir"); } @Override public void unwieldImp() { - System.out.println("unwielding Mjollnir"); + LOGGER.info("unwielding Mjollnir"); } @Override public void flyImp() { - System.out.println("Mjollnir hits the enemy in the air and returns back to the owner's hand"); + LOGGER.info("Mjollnir hits the enemy in the air and returns back to the owner's hand"); } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java b/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java index 91cad9cc2..e9d65bc8c 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java @@ -22,6 +22,9 @@ */ package com.iluwatar.bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Stormbringer @@ -29,23 +32,25 @@ package com.iluwatar.bridge; */ public class Stormbringer extends SoulEatingMagicWeaponImpl { + private static final Logger LOGGER = LoggerFactory.getLogger(Stormbringer.class); + @Override public void wieldImp() { - System.out.println("wielding Stormbringer"); + LOGGER.info("wielding Stormbringer"); } @Override public void swingImp() { - System.out.println("swinging Stormbringer"); + LOGGER.info("swinging Stormbringer"); } @Override public void unwieldImp() { - System.out.println("unwielding Stormbringer"); + LOGGER.info("unwielding Stormbringer"); } @Override public void eatSoulImp() { - System.out.println("Stormbringer devours the enemy's soul"); + LOGGER.info("Stormbringer devours the enemy's soul"); } } diff --git a/builder/src/main/java/com/iluwatar/builder/App.java b/builder/src/main/java/com/iluwatar/builder/App.java index d421de7b6..0790e3058 100644 --- a/builder/src/main/java/com/iluwatar/builder/App.java +++ b/builder/src/main/java/com/iluwatar/builder/App.java @@ -23,6 +23,8 @@ package com.iluwatar.builder; import com.iluwatar.builder.Hero.Builder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -50,6 +52,8 @@ import com.iluwatar.builder.Hero.Builder; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -60,18 +64,18 @@ public class App { Hero mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK) .withWeapon(Weapon.DAGGER).build(); - System.out.println(mage); + LOGGER.info(mage.toString()); Hero warrior = new Hero.Builder(Profession.WARRIOR, "Amberjill").withHairColor(HairColor.BLOND) .withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD) .build(); - System.out.println(warrior); + LOGGER.info(warrior.toString()); Hero thief = new Hero.Builder(Profession.THIEF, "Desmond").withHairType(HairType.BALD) .withWeapon(Weapon.BOW).build(); - System.out.println(thief); + LOGGER.info(thief.toString()); } } diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java index 7296f63b4..9c890b108 100644 --- a/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java +++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java @@ -22,6 +22,9 @@ */ package com.iluwatar.business.delegate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Service EJB implementation @@ -29,8 +32,10 @@ package com.iluwatar.business.delegate; */ public class EjbService implements BusinessService { + private static final Logger LOGGER = LoggerFactory.getLogger(EjbService.class); + @Override public void doProcessing() { - System.out.println("EjbService is now processing"); + LOGGER.info("EjbService is now processing"); } } diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java index 5b71ce57d..5b5fa6247 100644 --- a/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java +++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java @@ -22,6 +22,9 @@ */ package com.iluwatar.business.delegate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Service JMS implementation @@ -29,8 +32,10 @@ package com.iluwatar.business.delegate; */ public class JmsService implements BusinessService { + private static final Logger LOGGER = LoggerFactory.getLogger(JmsService.class); + @Override public void doProcessing() { - System.out.println("JmsService is now processing"); + LOGGER.info("JmsService is now processing"); } } diff --git a/caching/src/main/java/com/iluwatar/caching/App.java b/caching/src/main/java/com/iluwatar/caching/App.java index 8e5a84085..377a4bfa6 100644 --- a/caching/src/main/java/com/iluwatar/caching/App.java +++ b/caching/src/main/java/com/iluwatar/caching/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.caching; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing @@ -59,6 +62,9 @@ package com.iluwatar.caching; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** * Program entry point * @@ -80,13 +86,13 @@ public class App { * Read-through and write-through */ public void useReadAndWriteThroughStrategy() { - System.out.println("# CachingPolicy.THROUGH"); + LOGGER.info("# CachingPolicy.THROUGH"); AppManager.initCachingPolicy(CachingPolicy.THROUGH); UserAccount userAccount1 = new UserAccount("001", "John", "He is a boy."); AppManager.save(userAccount1); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("001"); AppManager.find("001"); } @@ -95,21 +101,21 @@ public class App { * Read-through and write-around */ public void useReadThroughAndWriteAroundStrategy() { - System.out.println("# CachingPolicy.AROUND"); + LOGGER.info("# CachingPolicy.AROUND"); AppManager.initCachingPolicy(CachingPolicy.AROUND); UserAccount userAccount2 = new UserAccount("002", "Jane", "She is a girl."); AppManager.save(userAccount2); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("002"); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); userAccount2 = AppManager.find("002"); userAccount2.setUserName("Jane G."); AppManager.save(userAccount2); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("002"); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("002"); } @@ -117,7 +123,7 @@ public class App { * Read-through and write-behind */ public void useReadThroughAndWriteBehindStrategy() { - System.out.println("# CachingPolicy.BEHIND"); + LOGGER.info("# CachingPolicy.BEHIND"); AppManager.initCachingPolicy(CachingPolicy.BEHIND); UserAccount userAccount3 = new UserAccount("003", "Adam", "He likes food."); @@ -127,13 +133,13 @@ public class App { AppManager.save(userAccount3); AppManager.save(userAccount4); AppManager.save(userAccount5); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("003"); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); UserAccount userAccount6 = new UserAccount("006", "Yasha", "She is an only child."); AppManager.save(userAccount6); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("004"); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); } } diff --git a/caching/src/main/java/com/iluwatar/caching/CacheStore.java b/caching/src/main/java/com/iluwatar/caching/CacheStore.java index 5903f8219..3b3226553 100644 --- a/caching/src/main/java/com/iluwatar/caching/CacheStore.java +++ b/caching/src/main/java/com/iluwatar/caching/CacheStore.java @@ -22,6 +22,9 @@ */ package com.iluwatar.caching; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.List; /** @@ -31,6 +34,8 @@ import java.util.List; */ public class CacheStore { + private static final Logger LOGGER = LoggerFactory.getLogger(CacheStore.class); + static LruCache cache; private CacheStore() { @@ -52,10 +57,10 @@ public class CacheStore { */ public static UserAccount readThrough(String userId) { if (cache.contains(userId)) { - System.out.println("# Cache Hit!"); + LOGGER.info("# Cache Hit!"); return cache.get(userId); } - System.out.println("# Cache Miss!"); + LOGGER.info("# Cache Miss!"); UserAccount userAccount = DbManager.readFromDb(userId); cache.set(userId, userAccount); return userAccount; @@ -91,13 +96,13 @@ public class CacheStore { */ public static UserAccount readThroughWithWriteBackPolicy(String userId) { if (cache.contains(userId)) { - System.out.println("# Cache Hit!"); + LOGGER.info("# Cache Hit!"); return cache.get(userId); } - System.out.println("# Cache Miss!"); + LOGGER.info("# Cache Miss!"); UserAccount userAccount = DbManager.readFromDb(userId); if (cache.isFull()) { - System.out.println("# Cache is FULL! Writing LRU data to DB..."); + LOGGER.info("# Cache is FULL! Writing LRU data to DB..."); UserAccount toBeWrittenToDb = cache.getLruData(); DbManager.upsertDb(toBeWrittenToDb); } @@ -110,7 +115,7 @@ public class CacheStore { */ public static void writeBehind(UserAccount userAccount) { if (cache.isFull() && !cache.contains(userAccount.getUserId())) { - System.out.println("# Cache is FULL! Writing LRU data to DB..."); + LOGGER.info("# Cache is FULL! Writing LRU data to DB..."); UserAccount toBeWrittenToDb = cache.getLruData(); DbManager.upsertDb(toBeWrittenToDb); } @@ -130,7 +135,7 @@ public class CacheStore { * Writes remaining content in the cache into the DB. */ public static void flushCache() { - System.out.println("# flushCache..."); + LOGGER.info("# flushCache..."); if (null == cache) { return; } diff --git a/caching/src/main/java/com/iluwatar/caching/LruCache.java b/caching/src/main/java/com/iluwatar/caching/LruCache.java index 5c5549afd..614b42ac4 100644 --- a/caching/src/main/java/com/iluwatar/caching/LruCache.java +++ b/caching/src/main/java/com/iluwatar/caching/LruCache.java @@ -22,6 +22,9 @@ */ package com.iluwatar.caching; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -38,6 +41,8 @@ import java.util.Map; */ public class LruCache { + private static final Logger LOGGER = LoggerFactory.getLogger(LruCache.class); + class Node { String userId; UserAccount userAccount; @@ -117,7 +122,7 @@ public class LruCache { } else { Node newNode = new Node(userId, userAccount); if (cache.size() >= capacity) { - System.out.println("# Cache is FULL! Removing " + end.userId + " from cache..."); + LOGGER.info("# Cache is FULL! Removing {} from cache...", end.userId); cache.remove(end.userId); // remove LRU data from cache. remove(end); setHead(newNode); @@ -136,7 +141,7 @@ public class LruCache { * Invalidate cache for user */ public void invalidate(String userId) { - System.out.println("# " + userId + " has been updated! Removing older version from cache..."); + LOGGER.info("# {} has been updated! Removing older version from cache...", userId); Node toBeRemoved = cache.get(userId); remove(toBeRemoved); cache.remove(userId); diff --git a/callback/src/main/java/com/iluwatar/callback/App.java b/callback/src/main/java/com/iluwatar/callback/App.java index bc1b2890e..ece6f8cce 100644 --- a/callback/src/main/java/com/iluwatar/callback/App.java +++ b/callback/src/main/java/com/iluwatar/callback/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.callback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Callback pattern is more native for functional languages where functions are treated as @@ -31,6 +34,8 @@ package com.iluwatar.callback; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ @@ -39,7 +44,7 @@ public class App { Callback callback = new Callback() { @Override public void call() { - System.out.println("I'm done now."); + LOGGER.info("I'm done now."); } }; task.executeWith(callback); diff --git a/callback/src/main/java/com/iluwatar/callback/LambdasApp.java b/callback/src/main/java/com/iluwatar/callback/LambdasApp.java index 78ca63e0b..33a49a461 100644 --- a/callback/src/main/java/com/iluwatar/callback/LambdasApp.java +++ b/callback/src/main/java/com/iluwatar/callback/LambdasApp.java @@ -22,6 +22,9 @@ */ package com.iluwatar.callback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * This example generates the exact same output as {@link App} however the callback has been @@ -30,12 +33,14 @@ package com.iluwatar.callback; */ public class LambdasApp { + private static final Logger LOGGER = LoggerFactory.getLogger(LambdasApp.class); + /** * Program entry point */ public static void main(String[] args) { Task task = new SimpleTask(); - Callback c = () -> System.out.println("I'm done now."); + Callback c = () -> LOGGER.info("I'm done now."); task.executeWith(c); } } diff --git a/callback/src/main/java/com/iluwatar/callback/SimpleTask.java b/callback/src/main/java/com/iluwatar/callback/SimpleTask.java index 2a7385607..2c56bea07 100644 --- a/callback/src/main/java/com/iluwatar/callback/SimpleTask.java +++ b/callback/src/main/java/com/iluwatar/callback/SimpleTask.java @@ -22,6 +22,9 @@ */ package com.iluwatar.callback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Implementation of task that need to be executed @@ -29,8 +32,10 @@ package com.iluwatar.callback; */ public class SimpleTask extends Task { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleTask.class); + @Override public void execute() { - System.out.println("Perform some important activity and after call the callback method."); + LOGGER.info("Perform some important activity and after call the callback method."); } } diff --git a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java index 78d68e5dc..2fd774f99 100644 --- a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java +++ b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java @@ -22,6 +22,9 @@ */ package com.iluwatar.chain; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * RequestHandler @@ -29,6 +32,8 @@ package com.iluwatar.chain; */ public abstract class RequestHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class); + private RequestHandler next; public RequestHandler(RequestHandler next) { @@ -45,7 +50,7 @@ public abstract class RequestHandler { } protected void printHandling(Request req) { - System.out.println(this + " handling request \"" + req + "\""); + LOGGER.info("{} handling request \"{}\"", this, req); } @Override diff --git a/command/src/main/java/com/iluwatar/command/Target.java b/command/src/main/java/com/iluwatar/command/Target.java index 2e49ab663..3bfbde926 100644 --- a/command/src/main/java/com/iluwatar/command/Target.java +++ b/command/src/main/java/com/iluwatar/command/Target.java @@ -22,6 +22,9 @@ */ package com.iluwatar.command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Base class for spell targets. @@ -29,6 +32,8 @@ package com.iluwatar.command; */ public abstract class Target { + private static final Logger LOGGER = LoggerFactory.getLogger(Target.class); + private Size size; private Visibility visibility; @@ -56,8 +61,6 @@ public abstract class Target { * Print status */ public void printStatus() { - System.out.println(String.format("%s, [size=%s] [visibility=%s]", this, getSize(), - getVisibility())); - System.out.println(); + LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility()); } } diff --git a/command/src/main/java/com/iluwatar/command/Wizard.java b/command/src/main/java/com/iluwatar/command/Wizard.java index bd0ef85d4..abfc49967 100644 --- a/command/src/main/java/com/iluwatar/command/Wizard.java +++ b/command/src/main/java/com/iluwatar/command/Wizard.java @@ -22,6 +22,9 @@ */ package com.iluwatar.command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Deque; import java.util.LinkedList; @@ -32,6 +35,8 @@ import java.util.LinkedList; */ public class Wizard { + private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class); + private Deque undoStack = new LinkedList<>(); private Deque redoStack = new LinkedList<>(); @@ -41,7 +46,7 @@ public class Wizard { * Cast spell */ public void castSpell(Command command, Target target) { - System.out.println(this + " casts " + command + " at " + target); + LOGGER.info("{} casts {} at {}", this, command, target); command.execute(target); undoStack.offerLast(command); } @@ -53,7 +58,7 @@ public class Wizard { if (!undoStack.isEmpty()) { Command previousSpell = undoStack.pollLast(); redoStack.offerLast(previousSpell); - System.out.println(this + " undoes " + previousSpell); + LOGGER.info("{} undoes {}", this, previousSpell); previousSpell.undo(); } } @@ -65,7 +70,7 @@ public class Wizard { if (!redoStack.isEmpty()) { Command previousSpell = redoStack.pollLast(); undoStack.offerLast(previousSpell); - System.out.println(this + " redoes " + previousSpell); + LOGGER.info("{} redoes {}", this, previousSpell); previousSpell.redo(); } } diff --git a/composite/src/main/java/com/iluwatar/composite/App.java b/composite/src/main/java/com/iluwatar/composite/App.java index cfe37876f..07d4f0b68 100644 --- a/composite/src/main/java/com/iluwatar/composite/App.java +++ b/composite/src/main/java/com/iluwatar/composite/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.composite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * The Composite pattern is a partitioning design pattern. The Composite pattern describes that a * group of objects is to be treated in the same way as a single instance of an object. The intent @@ -35,20 +38,22 @@ package com.iluwatar.composite; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * * @param args command line args */ public static void main(String[] args) { - System.out.println("Message from the orcs: "); + LOGGER.info("Message from the orcs: "); LetterComposite orcMessage = new Messenger().messageFromOrcs(); orcMessage.print(); - System.out.println("\n"); + LOGGER.info("\n"); - System.out.println("Message from the elves: "); + LOGGER.info("Message from the elves: "); LetterComposite elfMessage = new Messenger().messageFromElves(); elfMessage.print(); diff --git a/composite/src/main/java/com/iluwatar/composite/Letter.java b/composite/src/main/java/com/iluwatar/composite/Letter.java index d6a4005d2..c8a6ccfce 100644 --- a/composite/src/main/java/com/iluwatar/composite/Letter.java +++ b/composite/src/main/java/com/iluwatar/composite/Letter.java @@ -22,6 +22,9 @@ */ package com.iluwatar.composite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Letter @@ -29,6 +32,8 @@ package com.iluwatar.composite; */ public class Letter extends LetterComposite { + private static final Logger LOGGER = LoggerFactory.getLogger(Letter.class); + private char c; public Letter(char c) { @@ -37,7 +42,7 @@ public class Letter extends LetterComposite { @Override protected void printThisBefore() { - System.out.print(c); + LOGGER.info(String.valueOf(c)); } @Override diff --git a/composite/src/main/java/com/iluwatar/composite/Sentence.java b/composite/src/main/java/com/iluwatar/composite/Sentence.java index eea1d4b1d..ca8698f4f 100644 --- a/composite/src/main/java/com/iluwatar/composite/Sentence.java +++ b/composite/src/main/java/com/iluwatar/composite/Sentence.java @@ -22,6 +22,9 @@ */ package com.iluwatar.composite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.List; /** @@ -31,6 +34,8 @@ import java.util.List; */ public class Sentence extends LetterComposite { + private static final Logger LOGGER = LoggerFactory.getLogger(Sentence.class); + /** * Constructor */ @@ -47,6 +52,6 @@ public class Sentence extends LetterComposite { @Override protected void printThisAfter() { - System.out.print("."); + LOGGER.info("."); } } diff --git a/composite/src/main/java/com/iluwatar/composite/Word.java b/composite/src/main/java/com/iluwatar/composite/Word.java index 819f166dc..4e5cfb31d 100644 --- a/composite/src/main/java/com/iluwatar/composite/Word.java +++ b/composite/src/main/java/com/iluwatar/composite/Word.java @@ -22,6 +22,9 @@ */ package com.iluwatar.composite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.List; /** @@ -31,6 +34,8 @@ import java.util.List; */ public class Word extends LetterComposite { + private static final Logger LOGGER = LoggerFactory.getLogger(Word.class); + /** * Constructor */ @@ -42,7 +47,7 @@ public class Word extends LetterComposite { @Override protected void printThisBefore() { - System.out.print(" "); + LOGGER.info(" "); } @Override diff --git a/decorator/src/main/java/com/iluwatar/decorator/App.java b/decorator/src/main/java/com/iluwatar/decorator/App.java index bdc574fbc..2f0b1aa4e 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/App.java +++ b/decorator/src/main/java/com/iluwatar/decorator/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.decorator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Decorator pattern is a more flexible alternative to subclassing. The Decorator class @@ -36,6 +39,8 @@ package com.iluwatar.decorator; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -44,17 +49,17 @@ public class App { public static void main(String[] args) { // simple troll - System.out.println("A simple looking troll approaches."); + LOGGER.info("A simple looking troll approaches."); Hostile troll = new Troll(); troll.attack(); troll.fleeBattle(); - System.out.printf("Simple troll power %d.\n", troll.getAttackPower()); + LOGGER.info("Simple troll power {}.\n", troll.getAttackPower()); // change the behavior of the simple troll by adding a decorator - System.out.println("\nA smart looking troll surprises you."); + LOGGER.info("A smart looking troll surprises you."); Hostile smart = new SmartHostile(troll); smart.attack(); smart.fleeBattle(); - System.out.printf("Smart troll power %d.\n", smart.getAttackPower()); + LOGGER.info("Smart troll power {}.\n", smart.getAttackPower()); } } diff --git a/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java b/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java index 3b4b86276..9a4a136ad 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java +++ b/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java @@ -22,6 +22,9 @@ */ package com.iluwatar.decorator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * SmartHostile is a decorator for {@link Hostile} objects. The calls to the {@link Hostile} interface * are intercepted and decorated. Finally the calls are delegated to the decorated {@link Hostile} @@ -30,6 +33,8 @@ package com.iluwatar.decorator; */ public class SmartHostile implements Hostile { + private static final Logger LOGGER = LoggerFactory.getLogger(SmartHostile.class); + private Hostile decorated; public SmartHostile(Hostile decorated) { @@ -38,7 +43,7 @@ public class SmartHostile implements Hostile { @Override public void attack() { - System.out.println("It throws a rock at you!"); + LOGGER.info("It throws a rock at you!"); decorated.attack(); } @@ -50,7 +55,7 @@ public class SmartHostile implements Hostile { @Override public void fleeBattle() { - System.out.println("It calls for help!"); + LOGGER.info("It calls for help!"); decorated.fleeBattle(); } } diff --git a/decorator/src/main/java/com/iluwatar/decorator/Troll.java b/decorator/src/main/java/com/iluwatar/decorator/Troll.java index 628adda4b..0fff3b812 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/Troll.java +++ b/decorator/src/main/java/com/iluwatar/decorator/Troll.java @@ -22,6 +22,9 @@ */ package com.iluwatar.decorator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Troll implements {@link Hostile} interface directly. @@ -29,9 +32,11 @@ package com.iluwatar.decorator; */ public class Troll implements Hostile { + private static final Logger LOGGER = LoggerFactory.getLogger(Troll.class); + @Override public void attack() { - System.out.println("The troll swings at you with a club!"); + LOGGER.info("The troll swings at you with a club!"); } @Override @@ -41,6 +46,6 @@ public class Troll implements Hostile { @Override public void fleeBattle() { - System.out.println("The troll shrieks in horror and runs away!"); + LOGGER.info("The troll shrieks in horror and runs away!"); } } diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java index 5e3966d85..1664e86e4 100644 --- a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java @@ -23,6 +23,8 @@ package com.iluwatar.delegation.simple.printers; import com.iluwatar.delegation.simple.Printer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Specialised Implementation of {@link Printer} for a Canon Printer, in @@ -32,12 +34,14 @@ import com.iluwatar.delegation.simple.Printer; */ public class CanonPrinter implements Printer { + private static final Logger LOGGER = LoggerFactory.getLogger(CanonPrinter.class); + /** * {@inheritDoc} */ @Override public void print(String message) { - System.out.print("Canon Printer : " + message); + LOGGER.info("Canon Printer : {}", message); } } diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java index d37fbf613..f67f9defa 100644 --- a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java @@ -23,6 +23,8 @@ package com.iluwatar.delegation.simple.printers; import com.iluwatar.delegation.simple.Printer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Specialised Implementation of {@link Printer} for a Epson Printer, in @@ -32,12 +34,14 @@ import com.iluwatar.delegation.simple.Printer; */ public class EpsonPrinter implements Printer { + private static final Logger LOGGER = LoggerFactory.getLogger(EpsonPrinter.class); + /** * {@inheritDoc} */ @Override public void print(String message) { - System.out.print("Epson Printer : " + message); + LOGGER.info("Epson Printer : {}", message); } } diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java index f81debf62..fdd89081b 100644 --- a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java @@ -23,6 +23,8 @@ package com.iluwatar.delegation.simple.printers; import com.iluwatar.delegation.simple.Printer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Specialised Implementation of {@link Printer} for a HP Printer, in @@ -32,12 +34,14 @@ import com.iluwatar.delegation.simple.Printer; */ public class HpPrinter implements Printer { + private static final Logger LOGGER = LoggerFactory.getLogger(HpPrinter.class); + /** * {@inheritDoc} */ @Override public void print(String message) { - System.out.print("HP Printer : " + message); + LOGGER.info("HP Printer : {}", message); } } diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Tobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Tobacco.java index 74a564ab5..c003007e0 100644 --- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Tobacco.java +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Tobacco.java @@ -22,6 +22,9 @@ */ package com.iluwatar.dependency.injection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Tobacco abstraction @@ -29,8 +32,10 @@ package com.iluwatar.dependency.injection; */ public abstract class Tobacco { + private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class); + public void smoke(Wizard wizard) { - System.out.println(String.format("%s smoking %s", wizard.getClass().getSimpleName(), this - .getClass().getSimpleName())); + LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(), + this.getClass().getSimpleName()); } } diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java index 98309e181..9ce969037 100644 --- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java +++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.doublechecked.locking; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -40,6 +43,8 @@ import java.util.concurrent.TimeUnit; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -58,7 +63,7 @@ public class App { try { executorService.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.out.println("Error waiting for ExecutorService shutdown"); + LOGGER.error("Error waiting for ExecutorService shutdown"); } } } diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java index 176203a44..09a14d320 100644 --- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java +++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java @@ -22,6 +22,9 @@ */ package com.iluwatar.doublechecked.locking; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -35,6 +38,8 @@ import java.util.concurrent.locks.ReentrantLock; */ public class Inventory { + private static final Logger LOGGER = LoggerFactory.getLogger(Inventory.class); + private final int inventorySize; private final List items; private final Lock lock; @@ -57,8 +62,7 @@ public class Inventory { try { if (items.size() < inventorySize) { items.add(item); - System.out.println(Thread.currentThread() + ": items.size()=" + items.size() - + ", inventorySize=" + inventorySize); + LOGGER.info("{}: items.size()={}, inventorySize={}", Thread.currentThread(), items.size(), inventorySize); return true; } } finally { diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java index 40a0485a5..601b0fcc0 100644 --- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java +++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.doubledispatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.List; @@ -45,6 +48,8 @@ import java.util.List; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -58,8 +63,8 @@ public class App { objects.add(new SpaceStationMir(1, 1, 2, 2)); objects.add(new Meteoroid(10, 10, 15, 15)); objects.add(new SpaceStationIss(12, 12, 14, 14)); - objects.stream().forEach(o -> System.out.println(o)); - System.out.println(""); + objects.stream().forEach(o -> LOGGER.info(o.toString())); + LOGGER.info(""); // collision check objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> { @@ -67,10 +72,10 @@ public class App { o1.collision(o2); } })); - System.out.println(""); + LOGGER.info(""); // output eventual object statuses - objects.stream().forEach(o -> System.out.println(o)); - System.out.println(""); + objects.stream().forEach(o -> LOGGER.info(o.toString())); + LOGGER.info(""); } } diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java index cc68a85ec..fcda7f312 100644 --- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java +++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java @@ -22,6 +22,9 @@ */ package com.iluwatar.doubledispatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Meteoroid game object @@ -29,6 +32,8 @@ package com.iluwatar.doubledispatch; */ public class Meteoroid extends GameObject { + private static final Logger LOGGER = LoggerFactory.getLogger(Meteoroid.class); + public Meteoroid(int left, int top, int right, int bottom) { super(left, top, right, bottom); } @@ -40,25 +45,21 @@ public class Meteoroid extends GameObject { @Override public void collisionResolve(FlamingAsteroid asteroid) { - System.out.println(String.format("%s hits %s.", asteroid.getClass().getSimpleName(), this - .getClass().getSimpleName())); + LOGGER.info("{} hits {}.", asteroid.getClass().getSimpleName(), this.getClass().getSimpleName()); } @Override public void collisionResolve(Meteoroid meteoroid) { - System.out.println(String.format("%s hits %s.", meteoroid.getClass().getSimpleName(), this - .getClass().getSimpleName())); + LOGGER.info("{} hits {}.", meteoroid.getClass().getSimpleName(), this.getClass().getSimpleName()); } @Override public void collisionResolve(SpaceStationMir mir) { - System.out.println(String.format("%s hits %s.", mir.getClass().getSimpleName(), this.getClass() - .getSimpleName())); + LOGGER.info("{} hits {}.", mir.getClass().getSimpleName(), this.getClass().getSimpleName()); } @Override public void collisionResolve(SpaceStationIss iss) { - System.out.println(String.format("%s hits %s.", iss.getClass().getSimpleName(), this.getClass() - .getSimpleName())); + LOGGER.info("{} hits {}.", iss.getClass().getSimpleName(), this.getClass().getSimpleName()); } } diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java index e7a55d0ee..c1f750059 100644 --- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java +++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java @@ -22,6 +22,9 @@ */ package com.iluwatar.doubledispatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Space station Mir game object @@ -29,6 +32,8 @@ package com.iluwatar.doubledispatch; */ public class SpaceStationMir extends GameObject { + private static final Logger LOGGER = LoggerFactory.getLogger(SpaceStationMir.class); + public SpaceStationMir(int left, int top, int right, int bottom) { super(left, top, right, bottom); } @@ -40,31 +45,30 @@ public class SpaceStationMir extends GameObject { @Override public void collisionResolve(FlamingAsteroid asteroid) { - System.out.println(String.format("%s hits %s. %s is damaged! %s is set on fire!", asteroid - .getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass() - .getSimpleName(), this.getClass().getSimpleName())); + LOGGER.info("{} hits {}. {} is damaged! {} is set on fire!", asteroid.getClass().getSimpleName(), + this.getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName()); setDamaged(true); setOnFire(true); } @Override public void collisionResolve(Meteoroid meteoroid) { - System.out.println(String.format("%s hits %s. %s is damaged!", meteoroid.getClass() - .getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName())); + LOGGER.info("{} hits {}. {} is damaged!", meteoroid.getClass().getSimpleName(), + this.getClass().getSimpleName(), this.getClass().getSimpleName()); setDamaged(true); } @Override public void collisionResolve(SpaceStationMir mir) { - System.out.println(String.format("%s hits %s. %s is damaged!", mir.getClass().getSimpleName(), - this.getClass().getSimpleName(), this.getClass().getSimpleName())); + LOGGER.info("{} hits {}. {} is damaged!", mir.getClass().getSimpleName(), + this.getClass().getSimpleName(), this.getClass().getSimpleName()); setDamaged(true); } @Override public void collisionResolve(SpaceStationIss iss) { - System.out.println(String.format("%s hits %s. %s is damaged!", iss.getClass().getSimpleName(), - this.getClass().getSimpleName(), this.getClass().getSimpleName())); + LOGGER.info("{} hits {}. {} is damaged!", iss.getClass().getSimpleName(), + this.getClass().getSimpleName(), this.getClass().getSimpleName()); setDamaged(true); } } diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingJoffrey.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingJoffrey.java index fdda59693..1a0ad3345 100644 --- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingJoffrey.java +++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingJoffrey.java @@ -22,6 +22,9 @@ */ package com.iluwatar.event.aggregator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * KingJoffrey observes events from {@link KingsHand}. @@ -29,8 +32,10 @@ package com.iluwatar.event.aggregator; */ public class KingJoffrey implements EventObserver { + private static final Logger LOGGER = LoggerFactory.getLogger(KingJoffrey.class); + @Override public void onEvent(Event e) { - System.out.println("Received event from the King's Hand: " + e.toString()); + LOGGER.info("Received event from the King's Hand: {}", e.toString()); } } diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java index 3ef4e8255..ded6b76ce 100644 --- a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java +++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java @@ -24,17 +24,19 @@ package com.iluwatar.eda.handler; import com.iluwatar.eda.event.UserCreatedEvent; import com.iluwatar.eda.framework.Handler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Handles the {@link UserCreatedEvent} message. */ public class UserCreatedEventHandler implements Handler { + private static final Logger LOGGER = LoggerFactory.getLogger(UserCreatedEventHandler.class); + @Override public void onEvent(UserCreatedEvent event) { - - System.out.println(String.format( - "User '%s' has been Created!", event.getUser().getUsername())); + LOGGER.info("User '{}' has been Created!", event.getUser().getUsername()); } } diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java index 0311d5781..a0bf28c57 100644 --- a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java +++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java @@ -24,16 +24,18 @@ package com.iluwatar.eda.handler; import com.iluwatar.eda.event.UserUpdatedEvent; import com.iluwatar.eda.framework.Handler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Handles the {@link UserUpdatedEvent} message. */ public class UserUpdatedEventHandler implements Handler { + private static final Logger LOGGER = LoggerFactory.getLogger(UserUpdatedEventHandler.class); + @Override public void onEvent(UserUpdatedEvent event) { - - System.out.println(String.format( - "User '%s' has been Updated!", event.getUser().getUsername())); + LOGGER.info("User '{}' has been Updated!", event.getUser().getUsername()); } } diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java b/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java index bdc839f57..61e64a153 100644 --- a/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java +++ b/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java @@ -22,6 +22,9 @@ */ package com.iluwatar.facade; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * DwarvenCartOperator is one of the goldmine subsystems. @@ -29,9 +32,11 @@ package com.iluwatar.facade; */ public class DwarvenCartOperator extends DwarvenMineWorker { + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenCartOperator.class); + @Override public void work() { - System.out.println(name() + " moves gold chunks out of the mine."); + LOGGER.info("{} moves gold chunks out of the mine.", name()); } @Override diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java index 54fa821f4..2eb464edf 100644 --- a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java +++ b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java @@ -22,6 +22,9 @@ */ package com.iluwatar.facade; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * DwarvenGoldDigger is one of the goldmine subsystems. @@ -29,9 +32,11 @@ package com.iluwatar.facade; */ public class DwarvenGoldDigger extends DwarvenMineWorker { + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenGoldDigger.class); + @Override public void work() { - System.out.println(name() + " digs for gold."); + LOGGER.info("{} digs for gold.", name()); } @Override diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java b/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java index f27054c53..48ec1db48 100644 --- a/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java +++ b/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java @@ -22,6 +22,9 @@ */ package com.iluwatar.facade; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * DwarvenMineWorker is one of the goldmine subsystems. @@ -29,20 +32,22 @@ package com.iluwatar.facade; */ public abstract class DwarvenMineWorker { + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenMineWorker.class); + public void goToSleep() { - System.out.println(name() + " goes to sleep."); + LOGGER.info("{} goes to sleep.", name()); } public void wakeUp() { - System.out.println(name() + " wakes up."); + LOGGER.info("{} wakes up.", name()); } public void goHome() { - System.out.println(name() + " goes home."); + LOGGER.info("{} goes home.", name()); } public void goToMine() { - System.out.println(name() + " goes to the mine."); + LOGGER.info("{} goes to the mine.", name()); } private void action(Action action) { @@ -63,7 +68,7 @@ public abstract class DwarvenMineWorker { work(); break; default: - System.out.println("Undefined action"); + LOGGER.info("Undefined action"); break; } } diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java b/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java index 74d8b89cc..54fcca73a 100644 --- a/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java +++ b/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java @@ -22,6 +22,9 @@ */ package com.iluwatar.facade; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * DwarvenTunnelDigger is one of the goldmine subsystems. @@ -29,9 +32,11 @@ package com.iluwatar.facade; */ public class DwarvenTunnelDigger extends DwarvenMineWorker { + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenTunnelDigger.class); + @Override public void work() { - System.out.println(name() + " creates another promising tunnel."); + LOGGER.info("{} creates another promising tunnel.", name()); } @Override diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/App.java b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java index f27bee170..c091cb1eb 100644 --- a/factory-kit/src/main/java/com/iluwatar/factorykit/App.java +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.factorykit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Factory-kit is a creational pattern which defines a factory of immutable content * with separated builder and factory interfaces to deal with the problem of @@ -36,6 +39,9 @@ package com.iluwatar.factorykit; * be mapped explicitly with desired class type in the factory instance. */ public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point. * @@ -49,6 +55,6 @@ public class App { builder.add(WeaponType.BOW, Bow::new); }); Weapon axe = factory.create(WeaponType.AXE); - System.out.println(axe); + LOGGER.info(axe.toString()); } } diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/App.java b/factory-method/src/main/java/com/iluwatar/factory/method/App.java index cd7a6e6e7..a49d8bd32 100644 --- a/factory-method/src/main/java/com/iluwatar/factory/method/App.java +++ b/factory-method/src/main/java/com/iluwatar/factory/method/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.factory.method; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Factory Method is a creational design pattern which uses factory methods to deal with the @@ -38,6 +41,8 @@ package com.iluwatar.factory.method; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private final Blacksmith blacksmith; /** @@ -70,8 +75,8 @@ public class App { private void manufactureWeapons() { Weapon weapon; weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR); - System.out.println(weapon); + LOGGER.info(weapon.toString()); weapon = blacksmith.manufactureWeapon(WeaponType.AXE); - System.out.println(weapon); + LOGGER.info(weapon.toString()); } } diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java index debe99580..c2bccb851 100644 --- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java +++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java @@ -27,6 +27,8 @@ import com.iluwatar.featuretoggle.pattern.Service; import com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion; import com.iluwatar.featuretoggle.user.User; import com.iluwatar.featuretoggle.user.UserGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Properties; @@ -45,6 +47,8 @@ import java.util.Properties; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Block 1 shows the {@link PropertiesFeatureToggleVersion} being run with {@link Properties} setting the feature * toggle to enabled. @@ -70,7 +74,7 @@ public class App { properties.put("enhancedWelcome", true); Service service = new PropertiesFeatureToggleVersion(properties); final String welcomeMessage = service.getWelcomeMessage(new User("Jamie No Code")); - System.out.println(welcomeMessage); + LOGGER.info(welcomeMessage); // --------------------------------------------- @@ -78,7 +82,7 @@ public class App { turnedOff.put("enhancedWelcome", false); Service turnedOffService = new PropertiesFeatureToggleVersion(turnedOff); final String welcomeMessageturnedOff = turnedOffService.getWelcomeMessage(new User("Jamie No Code")); - System.out.println(welcomeMessageturnedOff); + LOGGER.info(welcomeMessageturnedOff); // -------------------------------------------- @@ -90,7 +94,7 @@ public class App { final String welcomeMessagePaidUser = service.getWelcomeMessage(paidUser); final String welcomeMessageFreeUser = service.getWelcomeMessage(freeUser); - System.out.println(welcomeMessageFreeUser); - System.out.println(welcomeMessagePaidUser); + LOGGER.info(welcomeMessageFreeUser); + LOGGER.info(welcomeMessagePaidUser); } } diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java index 1be2b1e70..30678359d 100644 --- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java @@ -35,6 +35,8 @@ import java.util.function.Predicate; import com.iluwatar.fluentinterface.fluentiterable.FluentIterable; import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable; import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. @@ -50,6 +52,8 @@ import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ @@ -74,9 +78,7 @@ public class App { .fromCopyOf(integerList) .filter(number -> number % 2 == 0) .first() - .ifPresent( - evenNumber -> System.out.println(String.format("The first even number is: %d", - evenNumber))); + .ifPresent(evenNumber -> LOGGER.info("The first even number is: {}", evenNumber)); List transformedList = @@ -97,9 +99,7 @@ public class App { .filter(negatives()) .first(2) .last() - .ifPresent( - lastOfFirstTwo -> System.out.println(String.format( - "The last of the first two negatives is: %d", lastOfFirstTwo))); + .ifPresent(lastOfFirstTwo -> LOGGER.info("The last of the first two negatives is: {}", lastOfFirstTwo)); } private static Function transformToString() { @@ -126,6 +126,6 @@ public class App { joiner.add(iterator.next().toString()); } - System.out.println(joiner); + LOGGER.info(joiner.toString()); } } diff --git a/flux/src/main/java/com/iluwatar/flux/view/ContentView.java b/flux/src/main/java/com/iluwatar/flux/view/ContentView.java index cb351bfae..dd5405a02 100644 --- a/flux/src/main/java/com/iluwatar/flux/view/ContentView.java +++ b/flux/src/main/java/com/iluwatar/flux/view/ContentView.java @@ -25,6 +25,8 @@ package com.iluwatar.flux.view; import com.iluwatar.flux.action.Content; import com.iluwatar.flux.store.ContentStore; import com.iluwatar.flux.store.Store; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -33,6 +35,8 @@ import com.iluwatar.flux.store.Store; */ public class ContentView implements View { + private static final Logger LOGGER = LoggerFactory.getLogger(ContentView.class); + private Content content = Content.PRODUCTS; @Override @@ -44,6 +48,6 @@ public class ContentView implements View { @Override public void render() { - System.out.println(content.toString()); + LOGGER.info(content.toString()); } } diff --git a/flux/src/main/java/com/iluwatar/flux/view/MenuView.java b/flux/src/main/java/com/iluwatar/flux/view/MenuView.java index 6cd9005dc..81d1e49d5 100644 --- a/flux/src/main/java/com/iluwatar/flux/view/MenuView.java +++ b/flux/src/main/java/com/iluwatar/flux/view/MenuView.java @@ -26,6 +26,8 @@ import com.iluwatar.flux.action.MenuItem; import com.iluwatar.flux.dispatcher.Dispatcher; import com.iluwatar.flux.store.MenuStore; import com.iluwatar.flux.store.Store; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -34,6 +36,8 @@ import com.iluwatar.flux.store.Store; */ public class MenuView implements View { + private static final Logger LOGGER = LoggerFactory.getLogger(MenuView.class); + private MenuItem selected = MenuItem.HOME; @Override @@ -47,9 +51,9 @@ public class MenuView implements View { public void render() { for (MenuItem item : MenuItem.values()) { if (selected.equals(item)) { - System.out.println(String.format("* %s", item.toString())); + LOGGER.info("* {}", item); } else { - System.out.println(item.toString()); + LOGGER.info(item.toString()); } } } diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java index 507de7a6a..5cde4c248 100644 --- a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java +++ b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java @@ -22,6 +22,9 @@ */ package com.iluwatar.flyweight; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -33,6 +36,8 @@ import java.util.List; */ public class AlchemistShop { + private static final Logger LOGGER = LoggerFactory.getLogger(AlchemistShop.class); + private List topShelf; private List bottomShelf; @@ -88,13 +93,13 @@ public class AlchemistShop { */ public void enumerate() { - System.out.println("Enumerating top shelf potions\n"); + LOGGER.info("Enumerating top shelf potions\n"); for (Potion p : topShelf) { p.drink(); } - System.out.println("\nEnumerating bottom shelf potions\n"); + LOGGER.info("Enumerating bottom shelf potions\n"); for (Potion p : bottomShelf) { p.drink(); diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/HealingPotion.java b/flyweight/src/main/java/com/iluwatar/flyweight/HealingPotion.java index 464675a61..e25107bdb 100644 --- a/flyweight/src/main/java/com/iluwatar/flyweight/HealingPotion.java +++ b/flyweight/src/main/java/com/iluwatar/flyweight/HealingPotion.java @@ -22,6 +22,9 @@ */ package com.iluwatar.flyweight; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * HealingPotion @@ -29,8 +32,10 @@ package com.iluwatar.flyweight; */ public class HealingPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(HealingPotion.class); + @Override public void drink() { - System.out.println("You feel healed. (Potion=" + System.identityHashCode(this) + ")"); + LOGGER.info("You feel healed. (Potion={})", System.identityHashCode(this)); } } diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/HolyWaterPotion.java b/flyweight/src/main/java/com/iluwatar/flyweight/HolyWaterPotion.java index b05b4af11..83a5ca6d1 100644 --- a/flyweight/src/main/java/com/iluwatar/flyweight/HolyWaterPotion.java +++ b/flyweight/src/main/java/com/iluwatar/flyweight/HolyWaterPotion.java @@ -22,6 +22,9 @@ */ package com.iluwatar.flyweight; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * HolyWaterPotion @@ -29,8 +32,10 @@ package com.iluwatar.flyweight; */ public class HolyWaterPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(HolyWaterPotion.class); + @Override public void drink() { - System.out.println("You feel blessed. (Potion=" + System.identityHashCode(this) + ")"); + LOGGER.info("You feel blessed. (Potion={})", System.identityHashCode(this)); } } diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/InvisibilityPotion.java b/flyweight/src/main/java/com/iluwatar/flyweight/InvisibilityPotion.java index 5aeb5d3a4..1e3087c4b 100644 --- a/flyweight/src/main/java/com/iluwatar/flyweight/InvisibilityPotion.java +++ b/flyweight/src/main/java/com/iluwatar/flyweight/InvisibilityPotion.java @@ -22,6 +22,9 @@ */ package com.iluwatar.flyweight; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * InvisibilityPotion @@ -29,8 +32,10 @@ package com.iluwatar.flyweight; */ public class InvisibilityPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(InvisibilityPotion.class); + @Override public void drink() { - System.out.println("You become invisible. (Potion=" + System.identityHashCode(this) + ")"); + LOGGER.info("You become invisible. (Potion={})", System.identityHashCode(this)); } } diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/PoisonPotion.java b/flyweight/src/main/java/com/iluwatar/flyweight/PoisonPotion.java index a9d13088e..83c32b192 100644 --- a/flyweight/src/main/java/com/iluwatar/flyweight/PoisonPotion.java +++ b/flyweight/src/main/java/com/iluwatar/flyweight/PoisonPotion.java @@ -22,6 +22,9 @@ */ package com.iluwatar.flyweight; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * PoisonPotion @@ -29,8 +32,10 @@ package com.iluwatar.flyweight; */ public class PoisonPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(PoisonPotion.class); + @Override public void drink() { - System.out.println("Urgh! This is poisonous. (Potion=" + System.identityHashCode(this) + ")"); + LOGGER.info("Urgh! This is poisonous. (Potion={})", System.identityHashCode(this)); } } diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/StrengthPotion.java b/flyweight/src/main/java/com/iluwatar/flyweight/StrengthPotion.java index 2c21e7df1..81f5a9d46 100644 --- a/flyweight/src/main/java/com/iluwatar/flyweight/StrengthPotion.java +++ b/flyweight/src/main/java/com/iluwatar/flyweight/StrengthPotion.java @@ -22,6 +22,9 @@ */ package com.iluwatar.flyweight; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * StrengthPotion @@ -29,8 +32,10 @@ package com.iluwatar.flyweight; */ public class StrengthPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(StrengthPotion.class); + @Override public void drink() { - System.out.println("You feel strong. (Potion=" + System.identityHashCode(this) + ")"); + LOGGER.info("You feel strong. (Potion={})", System.identityHashCode(this)); } } diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java b/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java index a7cf8ca27..ddd27d0e8 100644 --- a/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java +++ b/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java @@ -22,15 +22,20 @@ */ package com.iluwatar.front.controller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * View for archers. * */ public class ArcherView implements View { + + private static final Logger LOGGER = LoggerFactory.getLogger(ArcherView.class); @Override public void display() { - System.out.println("Displaying archers"); + LOGGER.info("Displaying archers"); } } diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java b/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java index 90e4c7896..f3b7e308e 100644 --- a/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java +++ b/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java @@ -22,6 +22,9 @@ */ package com.iluwatar.front.controller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * View for catapults. @@ -29,8 +32,10 @@ package com.iluwatar.front.controller; */ public class CatapultView implements View { + private static final Logger LOGGER = LoggerFactory.getLogger(CatapultView.class); + @Override public void display() { - System.out.println("Displaying catapults"); + LOGGER.info("Displaying catapults"); } } diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java b/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java index cbfd4bd2e..00dbc582b 100644 --- a/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java +++ b/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java @@ -22,6 +22,9 @@ */ package com.iluwatar.front.controller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * View for errors. @@ -29,8 +32,10 @@ package com.iluwatar.front.controller; */ public class ErrorView implements View { + private static final Logger LOGGER = LoggerFactory.getLogger(ErrorView.class); + @Override public void display() { - System.out.println("Error 500"); + LOGGER.error("Error 500"); } } diff --git a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java index 17839bb32..3186b292a 100644 --- a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java +++ b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.halfsynchalfasync; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.LinkedBlockingQueue; /** @@ -66,6 +69,8 @@ import java.util.concurrent.LinkedBlockingQueue; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -128,7 +133,7 @@ public class App { @Override public void onPostCall(Long result) { // Handle the result of computation - System.out.println(result); + LOGGER.info(result.toString()); } @Override @@ -141,7 +146,7 @@ public class App { try { Thread.sleep(i); } catch (InterruptedException e) { - System.out.println(e); + LOGGER.error("Exception caught.", e); } return i * (i + 1) / 2; } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java index ea2f33699..e83521c22 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/administration/ConsoleAdministration.java @@ -30,6 +30,8 @@ import com.iluwatar.hexagonal.domain.LotteryService; import com.iluwatar.hexagonal.module.LotteryModule; import com.iluwatar.hexagonal.mongo.MongoConnectionPropertiesLoader; import com.iluwatar.hexagonal.sampledata.SampleData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Scanner; @@ -38,6 +40,8 @@ import java.util.Scanner; */ public class ConsoleAdministration { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleAdministration.class); + /** * Program entry point */ @@ -53,29 +57,29 @@ public class ConsoleAdministration { printMainMenu(); String cmd = readString(scanner); if (cmd.equals("1")) { - administartion.getAllSubmittedTickets().forEach((k,v)->System.out.println("Key: " + k + " Value: " + v)); + administartion.getAllSubmittedTickets().forEach((k,v)->LOGGER.info("Key: {}, Value: {}", k, v)); } else if (cmd.equals("2")) { LotteryNumbers numbers = administartion.performLottery(); - System.out.println("The winning numbers: " + numbers.getNumbersAsString()); - System.out.println("Time to reset the database for next round, eh?"); + LOGGER.info("The winning numbers: {}", numbers.getNumbersAsString()); + LOGGER.info("Time to reset the database for next round, eh?"); } else if (cmd.equals("3")) { administartion.resetLottery(); - System.out.println("The lottery ticket database was cleared."); + LOGGER.info("The lottery ticket database was cleared."); } else if (cmd.equals("4")) { exit = true; } else { - System.out.println("Unknown command: " + cmd); + LOGGER.info("Unknown command: {}", cmd); } } } private static void printMainMenu() { - System.out.println(""); - System.out.println("### Lottery Administration Console ###"); - System.out.println("(1) Show all submitted tickets"); - System.out.println("(2) Perform lottery draw"); - System.out.println("(3) Reset lottery ticket database"); - System.out.println("(4) Exit"); + LOGGER.info(""); + LOGGER.info("### Lottery Administration Console ###"); + LOGGER.info("(1) Show all submitted tickets"); + LOGGER.info("(2) Perform lottery draw"); + LOGGER.info("(3) Reset lottery ticket database"); + LOGGER.info("(4) Exit"); } private static String readString(Scanner scanner) { diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/StdOutEventLog.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/StdOutEventLog.java index 4150dd401..c63759e8e 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/StdOutEventLog.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/StdOutEventLog.java @@ -23,42 +23,42 @@ package com.iluwatar.hexagonal.eventlog; import com.iluwatar.hexagonal.domain.PlayerDetails; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Standard output event log */ public class StdOutEventLog implements LotteryEventLog { + private static final Logger LOGGER = LoggerFactory.getLogger(StdOutEventLog.class); + @Override public void ticketSubmitted(PlayerDetails details) { - System.out.println(String.format("Lottery ticket for %s was submitted. Bank account %s was charged for 3 credits.", - details.getEmail(), details.getBankAccount())); + LOGGER.info("Lottery ticket for {} was submitted. Bank account {} was charged for 3 credits.", + details.getEmail(), details.getBankAccount()); } @Override public void ticketDidNotWin(PlayerDetails details) { - System.out.println(String.format("Lottery ticket for %s was checked and unfortunately did not win this time.", - details.getEmail())); + LOGGER.info("Lottery ticket for {} was checked and unfortunately did not win this time.", details.getEmail()); } @Override public void ticketWon(PlayerDetails details, int prizeAmount) { - System.out - .println(String.format("Lottery ticket for %s has won! The bank account %s was deposited with %d credits.", - details.getEmail(), details.getBankAccount(), prizeAmount)); + LOGGER.info("Lottery ticket for {} has won! The bank account {} was deposited with {} credits.", + details.getEmail(), details.getBankAccount(), prizeAmount); } @Override public void prizeError(PlayerDetails details, int prizeAmount) { - System.out - .println(String.format("Lottery ticket for %s has won! Unfortunately the bank credit transfer of %d failed.", - details.getEmail(), prizeAmount)); + LOGGER.error("Lottery ticket for {} has won! Unfortunately the bank credit transfer of {} failed.", + details.getEmail(), prizeAmount); } @Override public void ticketSubmitError(PlayerDetails details) { - System.out.println( - String.format("Lottery ticket for %s could not be submitted because the credit transfer of 3 credits failed.", - details.getEmail())); + LOGGER.error("Lottery ticket for {} could not be submitted because the credit transfer of 3 credits failed.", + details.getEmail()); } } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index cc13d389d..00d61b668 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -24,6 +24,7 @@ package com.iluwatar.hexagonal.service; import com.google.inject.Guice; import com.google.inject.Injector; +import com.iluwatar.hexagonal.administration.ConsoleAdministration; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryService; @@ -33,6 +34,8 @@ import com.iluwatar.hexagonal.domain.LotteryTicketId; import com.iluwatar.hexagonal.domain.PlayerDetails; import com.iluwatar.hexagonal.module.LotteryModule; import com.iluwatar.hexagonal.mongo.MongoConnectionPropertiesLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.HashSet; import java.util.Optional; @@ -44,6 +47,7 @@ import java.util.Set; */ public class ConsoleLottery { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleLottery.class); /** * Program entry point @@ -59,25 +63,25 @@ public class ConsoleLottery { printMainMenu(); String cmd = readString(scanner); if (cmd.equals("1")) { - System.out.println("What is the account number?"); + LOGGER.info("What is the account number?"); String account = readString(scanner); - System.out.println(String.format("The account %s has %d credits.", account, bank.getFunds(account))); + LOGGER.info("The account {} has {} credits.", account, bank.getFunds(account)); } else if (cmd.equals("2")) { - System.out.println("What is the account number?"); + LOGGER.info("What is the account number?"); String account = readString(scanner); - System.out.println("How many credits do you want to deposit?"); + LOGGER.info("How many credits do you want to deposit?"); String amount = readString(scanner); bank.setFunds(account, Integer.parseInt(amount)); - System.out.println(String.format("The account %s now has %d credits.", account, bank.getFunds(account))); + LOGGER.info("The account {} now has {} credits.", account, bank.getFunds(account)); } else if (cmd.equals("3")) { - System.out.println("What is your email address?"); + LOGGER.info("What is your email address?"); String email = readString(scanner); - System.out.println("What is your bank account number?"); + LOGGER.info("What is your bank account number?"); String account = readString(scanner); - System.out.println("What is your phone number?"); + LOGGER.info("What is your phone number?"); String phone = readString(scanner); PlayerDetails details = new PlayerDetails(email, account, phone); - System.out.println("Give 4 comma separated lottery numbers?"); + LOGGER.info("Give 4 comma separated lottery numbers?"); String numbers = readString(scanner); try { String[] parts = numbers.split(","); @@ -89,17 +93,17 @@ public class ConsoleLottery { LotteryTicket lotteryTicket = new LotteryTicket(new LotteryTicketId(), details, lotteryNumbers); Optional id = service.submitTicket(lotteryTicket); if (id.isPresent()) { - System.out.println("Submitted lottery ticket with id: " + id.get()); + LOGGER.info("Submitted lottery ticket with id: {}", id.get()); } else { - System.out.println("Failed submitting lottery ticket - please try again."); + LOGGER.info("Failed submitting lottery ticket - please try again."); } } catch (Exception e) { - System.out.println("Failed submitting lottery ticket - please try again."); + LOGGER.info("Failed submitting lottery ticket - please try again."); } } else if (cmd.equals("4")) { - System.out.println("What is the ID of the lottery ticket?"); + LOGGER.info("What is the ID of the lottery ticket?"); String id = readString(scanner); - System.out.println("Give the 4 comma separated winning numbers?"); + LOGGER.info("Give the 4 comma separated winning numbers?"); String numbers = readString(scanner); try { String[] parts = numbers.split(","); @@ -110,31 +114,31 @@ public class ConsoleLottery { LotteryTicketCheckResult result = service.checkTicketForPrize( new LotteryTicketId(Integer.parseInt(id)), LotteryNumbers.create(winningNumbers)); if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.WIN_PRIZE)) { - System.out.println("Congratulations! The lottery ticket has won!"); + LOGGER.info("Congratulations! The lottery ticket has won!"); } else if (result.getResult().equals(LotteryTicketCheckResult.CheckResult.NO_PRIZE)) { - System.out.println("Unfortunately the lottery ticket did not win."); + LOGGER.info("Unfortunately the lottery ticket did not win."); } else { - System.out.println("Such lottery ticket has not been submitted."); + LOGGER.info("Such lottery ticket has not been submitted."); } } catch (Exception e) { - System.out.println("Failed checking the lottery ticket - please try again."); + LOGGER.info("Failed checking the lottery ticket - please try again."); } } else if (cmd.equals("5")) { exit = true; } else { - System.out.println("Unknown command"); + LOGGER.info("Unknown command"); } } } private static void printMainMenu() { - System.out.println(""); - System.out.println("### Lottery Service Console ###"); - System.out.println("(1) Query lottery account funds"); - System.out.println("(2) Add funds to lottery account"); - System.out.println("(3) Submit ticket"); - System.out.println("(4) Check ticket"); - System.out.println("(5) Exit"); + LOGGER.info(""); + LOGGER.info("### Lottery Service Console ###"); + LOGGER.info("(1) Query lottery account funds"); + LOGGER.info("(2) Add funds to lottery account"); + LOGGER.info("(3) Submit ticket"); + LOGGER.info("(4) Check ticket"); + LOGGER.info("(5) Exit"); } private static String readString(Scanner scanner) { diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/App.java b/interpreter/src/main/java/com/iluwatar/interpreter/App.java index 708f06e6f..1cf732b0d 100644 --- a/interpreter/src/main/java/com/iluwatar/interpreter/App.java +++ b/interpreter/src/main/java/com/iluwatar/interpreter/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.interpreter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Stack; /** @@ -37,6 +40,8 @@ import java.util.Stack; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * * Program entry point. @@ -56,21 +61,21 @@ public class App { if (isOperator(s)) { Expression rightExpression = stack.pop(); Expression leftExpression = stack.pop(); - System.out.println(String.format("popped from stack left: %d right: %d", - leftExpression.interpret(), rightExpression.interpret())); + LOGGER.info("popped from stack left: {} right: {}", + leftExpression.interpret(), rightExpression.interpret()); Expression operator = getOperatorInstance(s, leftExpression, rightExpression); - System.out.println(String.format("operator: %s", operator)); + LOGGER.info("operator: {}", operator); int result = operator.interpret(); NumberExpression resultExpression = new NumberExpression(result); stack.push(resultExpression); - System.out.println(String.format("push result to stack: %d", resultExpression.interpret())); + LOGGER.info("push result to stack: {}", resultExpression.interpret()); } else { Expression i = new NumberExpression(s); stack.push(i); - System.out.println(String.format("push to stack: %d", i.interpret())); + LOGGER.info("push to stack: {}", i.interpret()); } } - System.out.println(String.format("result: %d", stack.pop().interpret())); + LOGGER.info("result: {}", stack.pop().interpret()); } public static boolean isOperator(String s) { diff --git a/iterator/src/main/java/com/iluwatar/iterator/App.java b/iterator/src/main/java/com/iluwatar/iterator/App.java index 8da0a7433..44bc1dacd 100644 --- a/iterator/src/main/java/com/iluwatar/iterator/App.java +++ b/iterator/src/main/java/com/iluwatar/iterator/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.iterator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Iterator pattern is a design pattern in which an iterator is used to traverse a container and @@ -34,6 +37,8 @@ package com.iluwatar.iterator; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -44,28 +49,28 @@ public class App { ItemIterator ringIterator = chest.iterator(ItemType.RING); while (ringIterator.hasNext()) { - System.out.println(ringIterator.next()); + LOGGER.info(ringIterator.next().toString()); } - System.out.println("----------"); + LOGGER.info("----------"); ItemIterator potionIterator = chest.iterator(ItemType.POTION); while (potionIterator.hasNext()) { - System.out.println(potionIterator.next()); + LOGGER.info(potionIterator.next().toString()); } - System.out.println("----------"); + LOGGER.info("----------"); ItemIterator weaponIterator = chest.iterator(ItemType.WEAPON); while (weaponIterator.hasNext()) { - System.out.println(weaponIterator.next()); + LOGGER.info(weaponIterator.next().toString()); } - System.out.println("----------"); + LOGGER.info("----------"); ItemIterator it = chest.iterator(ItemType.ANY); while (it.hasNext()) { - System.out.println(it.next()); + LOGGER.info(it.next().toString()); } } } diff --git a/layers/src/main/java/com/iluwatar/layers/CakeViewImpl.java b/layers/src/main/java/com/iluwatar/layers/CakeViewImpl.java index bc489e16e..bb636af7a 100644 --- a/layers/src/main/java/com/iluwatar/layers/CakeViewImpl.java +++ b/layers/src/main/java/com/iluwatar/layers/CakeViewImpl.java @@ -22,6 +22,9 @@ */ package com.iluwatar.layers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * View implementation for displaying cakes @@ -29,6 +32,8 @@ package com.iluwatar.layers; */ public class CakeViewImpl implements View { + private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class); + private CakeBakingService cakeBakingService; public CakeViewImpl(CakeBakingService cakeBakingService) { @@ -36,6 +41,6 @@ public class CakeViewImpl implements View { } public void render() { - cakeBakingService.getAllCakes().stream().forEach(cake -> System.out.println(cake)); + cakeBakingService.getAllCakes().stream().forEach(cake -> LOGGER.info(cake.toString())); } } diff --git a/layers/src/test/java/com/iluwatar/layers/StdOutTest.java b/layers/src/test/java/com/iluwatar/layers/StdOutTest.java index 3c94b178c..67a554873 100644 --- a/layers/src/test/java/com/iluwatar/layers/StdOutTest.java +++ b/layers/src/test/java/com/iluwatar/layers/StdOutTest.java @@ -24,6 +24,8 @@ package com.iluwatar.layers; import org.junit.After; import org.junit.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.PrintStream; diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/App.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/App.java index 7a658a8c6..b33520243 100644 --- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/App.java +++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.lazy.loading; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Lazy loading idiom defers object creation until needed. @@ -33,6 +36,9 @@ package com.iluwatar.lazy.loading; * */ public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -43,16 +49,16 @@ public class App { // Simple lazy loader - not thread safe HolderNaive holderNaive = new HolderNaive(); Heavy heavy = holderNaive.getHeavy(); - System.out.println("heavy=" + heavy); + LOGGER.info("heavy={}", heavy); // Thread safe lazy loader, but with heavy synchronization on each access HolderThreadSafe holderThreadSafe = new HolderThreadSafe(); Heavy another = holderThreadSafe.getHeavy(); - System.out.println("another=" + another); + LOGGER.info("another={}", another); // The most efficient lazy loader utilizing Java 8 features Java8Holder java8Holder = new Java8Holder(); Heavy next = java8Holder.getHeavy(); - System.out.println("next=" + next); + LOGGER.info("next={}", next); } } diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java index 57e8e263e..ad4eb3de2 100644 --- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java +++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java @@ -22,6 +22,9 @@ */ package com.iluwatar.lazy.loading; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Heavy objects are expensive to create. @@ -29,16 +32,18 @@ package com.iluwatar.lazy.loading; */ public class Heavy { + private static final Logger LOGGER = LoggerFactory.getLogger(Heavy.class); + /** * Constructor */ public Heavy() { - System.out.println("Creating Heavy ..."); + LOGGER.info("Creating Heavy ..."); try { Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("Exception caught.", e); } - System.out.println("... Heavy created"); + LOGGER.info("... Heavy created"); } } diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java index 75c65d1b9..0e3d2c718 100644 --- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java +++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java @@ -22,6 +22,9 @@ */ package com.iluwatar.lazy.loading; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Simple implementation of the lazy loading idiom. However, this is not thread safe. @@ -29,13 +32,15 @@ package com.iluwatar.lazy.loading; */ public class HolderNaive { + private static final Logger LOGGER = LoggerFactory.getLogger(HolderNaive.class); + private Heavy heavy; /** * Constructor */ public HolderNaive() { - System.out.println("HolderNaive created"); + LOGGER.info("HolderNaive created"); } /** diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java index c6e0fcfd9..35dd2e4f0 100644 --- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java +++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java @@ -22,6 +22,9 @@ */ package com.iluwatar.lazy.loading; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Same as HolderNaive but with added synchronization. This implementation is thread safe, but each @@ -30,13 +33,15 @@ package com.iluwatar.lazy.loading; */ public class HolderThreadSafe { + private static final Logger LOGGER = LoggerFactory.getLogger(HolderThreadSafe.class); + private Heavy heavy; /** * Constructor */ public HolderThreadSafe() { - System.out.println("HolderThreadSafe created"); + LOGGER.info("HolderThreadSafe created"); } /** diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java index e4ce394cc..95e8856c9 100644 --- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java +++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java @@ -22,6 +22,9 @@ */ package com.iluwatar.lazy.loading; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.function.Supplier; /** @@ -32,10 +35,12 @@ import java.util.function.Supplier; */ public class Java8Holder { + private static final Logger LOGGER = LoggerFactory.getLogger(Java8Holder.class); + private Supplier heavy = () -> createAndCacheHeavy(); public Java8Holder() { - System.out.println("Java8Holder created"); + LOGGER.info("Java8Holder created"); } public Heavy getHeavy() { diff --git a/mediator/src/main/java/com/iluwatar/mediator/PartyMemberBase.java b/mediator/src/main/java/com/iluwatar/mediator/PartyMemberBase.java index 7d3ca3dbf..9d9b9cd2d 100644 --- a/mediator/src/main/java/com/iluwatar/mediator/PartyMemberBase.java +++ b/mediator/src/main/java/com/iluwatar/mediator/PartyMemberBase.java @@ -22,6 +22,9 @@ */ package com.iluwatar.mediator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Abstract base class for party members. @@ -29,23 +32,25 @@ package com.iluwatar.mediator; */ public abstract class PartyMemberBase implements PartyMember { + private static final Logger LOGGER = LoggerFactory.getLogger(PartyMemberBase.class); + protected Party party; @Override public void joinedParty(Party party) { - System.out.println(this + " joins the party"); + LOGGER.info("{} joins the party", this); this.party = party; } @Override public void partyAction(Action action) { - System.out.println(this + " " + action.getDescription()); + LOGGER.info("{} {}", this, action.getDescription()); } @Override public void act(Action action) { if (party != null) { - System.out.println(this + " " + action.toString()); + LOGGER.info("{} {}", this, action); party.act(this, action); } } diff --git a/memento/src/main/java/com/iluwatar/memento/App.java b/memento/src/main/java/com/iluwatar/memento/App.java index e1ee349b1..c346b7941 100644 --- a/memento/src/main/java/com/iluwatar/memento/App.java +++ b/memento/src/main/java/com/iluwatar/memento/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.memento; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Stack; /** @@ -45,6 +48,8 @@ import java.util.Stack; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ @@ -52,22 +57,22 @@ public class App { Stack states = new Stack<>(); Star star = new Star(StarType.SUN, 10000000, 500000); - System.out.println(star); + LOGGER.info(star.toString()); states.add(star.getMemento()); star.timePasses(); - System.out.println(star); + LOGGER.info(star.toString()); states.add(star.getMemento()); star.timePasses(); - System.out.println(star); + LOGGER.info(star.toString()); states.add(star.getMemento()); star.timePasses(); - System.out.println(star); + LOGGER.info(star.toString()); states.add(star.getMemento()); star.timePasses(); - System.out.println(star); + LOGGER.info(star.toString()); while (states.size() > 0) { star.setMemento(states.pop()); - System.out.println(star); + LOGGER.info(star.toString()); } } } diff --git a/message-channel/src/main/java/com/iluwatar/message/channel/App.java b/message-channel/src/main/java/com/iluwatar/message/channel/App.java index dab04bd37..2e132213d 100644 --- a/message-channel/src/main/java/com/iluwatar/message/channel/App.java +++ b/message-channel/src/main/java/com/iluwatar/message/channel/App.java @@ -25,6 +25,8 @@ package com.iluwatar.message.channel; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -50,6 +52,8 @@ import org.apache.camel.impl.DefaultCamelContext; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ @@ -66,7 +70,7 @@ public class App { }); context.start(); - context.getRoutes().stream().forEach(r -> System.out.println(r)); + context.getRoutes().stream().forEach(r -> LOGGER.info(r.toString())); context.stop(); } } diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantView.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantView.java index dd4361487..61815aab8 100644 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantView.java +++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantView.java @@ -22,6 +22,9 @@ */ package com.iluwatar.model.view.controller; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * GiantView displays the giant @@ -29,7 +32,9 @@ package com.iluwatar.model.view.controller; */ public class GiantView { + private static final Logger LOGGER = LoggerFactory.getLogger(GiantView.class); + public void displayGiant(GiantModel giant) { - System.out.println(giant); + LOGGER.info(giant.toString()); } } diff --git a/monad/src/main/java/com/iluwatar/monad/App.java b/monad/src/main/java/com/iluwatar/monad/App.java index 7b28fdcf8..e707156d6 100644 --- a/monad/src/main/java/com/iluwatar/monad/App.java +++ b/monad/src/main/java/com/iluwatar/monad/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.monad; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; @@ -42,6 +45,8 @@ import java.util.function.Predicate; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point. * @@ -49,7 +54,7 @@ public class App { */ public static void main(String[] args) { User user = new User("user", 24, Sex.FEMALE, "foobar.com"); - System.out.println(Validator.of(user).validate(User::getName, Objects::nonNull, "name is null") + LOGGER.info(Validator.of(user).validate(User::getName, Objects::nonNull, "name is null") .validate(User::getName, name -> !name.isEmpty(), "name is empty") .validate(User::getEmail, email -> !email.contains("@"), "email doesn't containt '@'") .validate(User::getAge, age -> age > 20 && age < 30, "age isn't between...").get().toString()); diff --git a/monostate/src/main/java/com/iluwatar/monostate/Server.java b/monostate/src/main/java/com/iluwatar/monostate/Server.java index bf700a57a..86a4985cc 100644 --- a/monostate/src/main/java/com/iluwatar/monostate/Server.java +++ b/monostate/src/main/java/com/iluwatar/monostate/Server.java @@ -22,6 +22,9 @@ */ package com.iluwatar.monostate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Server class. Each Server sits behind a LoadBalancer which delegates the call to the servers @@ -29,6 +32,9 @@ package com.iluwatar.monostate; * */ public class Server { + + private static final Logger LOGGER = LoggerFactory.getLogger(Server.class); + public final String host; public final int port; public final int id; @@ -51,7 +57,7 @@ public class Server { } public void serve(Request request) { - System.out.println("Server ID " + id + " associated to host : " + getHost() + " and Port " - + getPort() + " Processed request with value " + request.value); + LOGGER.info("Server ID {} associated to host : {} and port {}. Processed request with value {}", + id, host, port, request.value); } } diff --git a/multiton/src/main/java/com/iluwatar/multiton/App.java b/multiton/src/main/java/com/iluwatar/multiton/App.java index 1ffd57a34..55cc8a2aa 100644 --- a/multiton/src/main/java/com/iluwatar/multiton/App.java +++ b/multiton/src/main/java/com/iluwatar/multiton/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.multiton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Whereas Singleton design pattern introduces single globally accessible object the Multiton @@ -35,20 +38,22 @@ package com.iluwatar.multiton; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * * @param args command line args */ public static void main(String[] args) { - System.out.println("KHAMUL=" + Nazgul.getInstance(NazgulName.KHAMUL)); - System.out.println("MURAZOR=" + Nazgul.getInstance(NazgulName.MURAZOR)); - System.out.println("DWAR=" + Nazgul.getInstance(NazgulName.DWAR)); - System.out.println("JI_INDUR=" + Nazgul.getInstance(NazgulName.JI_INDUR)); - System.out.println("AKHORAHIL=" + Nazgul.getInstance(NazgulName.AKHORAHIL)); - System.out.println("HOARMURATH=" + Nazgul.getInstance(NazgulName.HOARMURATH)); - System.out.println("ADUNAPHEL=" + Nazgul.getInstance(NazgulName.ADUNAPHEL)); - System.out.println("REN=" + Nazgul.getInstance(NazgulName.REN)); - System.out.println("UVATHA=" + Nazgul.getInstance(NazgulName.UVATHA)); + LOGGER.info("KHAMUL={}", Nazgul.getInstance(NazgulName.KHAMUL)); + LOGGER.info("MURAZOR={}", Nazgul.getInstance(NazgulName.MURAZOR)); + LOGGER.info("DWAR={}", Nazgul.getInstance(NazgulName.DWAR)); + LOGGER.info("JI_INDUR={}", Nazgul.getInstance(NazgulName.JI_INDUR)); + LOGGER.info("AKHORAHIL={}", Nazgul.getInstance(NazgulName.AKHORAHIL)); + LOGGER.info("HOARMURATH={}", Nazgul.getInstance(NazgulName.HOARMURATH)); + LOGGER.info("ADUNAPHEL={}", Nazgul.getInstance(NazgulName.ADUNAPHEL)); + LOGGER.info("REN={}", Nazgul.getInstance(NazgulName.REN)); + LOGGER.info("UVATHA={}", Nazgul.getInstance(NazgulName.UVATHA)); } } diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/App.java b/mute-idiom/src/main/java/com/iluwatar/mute/App.java index 8a2aca41e..35c9d2a55 100644 --- a/mute-idiom/src/main/java/com/iluwatar/mute/App.java +++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java @@ -23,6 +23,9 @@ package com.iluwatar.mute; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.sql.SQLException; @@ -46,6 +49,8 @@ import java.sql.SQLException; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point. * @@ -88,7 +93,7 @@ public class App { } private static void utilizeResource(Resource resource) throws SQLException { - System.out.println("Utilizing acquired resource: " + resource); + LOGGER.info("Utilizing acquired resource: {}", resource); } private static Resource acquireResource() throws SQLException { diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java index 58cbfe893..a7a010c3c 100644 --- a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java +++ b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java @@ -32,9 +32,13 @@ import java.io.PrintStream; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MuteTest { + private static final Logger LOGGER = LoggerFactory.getLogger(MuteTest.class); + private static final String MESSAGE = "should not occur"; @Rule public ExpectedException exception = ExpectedException.none(); @@ -69,7 +73,7 @@ public class MuteTest { private void methodNotThrowingAnyException() { - System.out.println("Executed successfully"); + LOGGER.info("Executed successfully"); } private void methodThrowingException() throws Exception { diff --git a/mutex/src/main/java/com/iluwatar/mutex/Thief.java b/mutex/src/main/java/com/iluwatar/mutex/Thief.java index d2225876c..d31ec3fa8 100644 --- a/mutex/src/main/java/com/iluwatar/mutex/Thief.java +++ b/mutex/src/main/java/com/iluwatar/mutex/Thief.java @@ -22,12 +22,17 @@ */ package com.iluwatar.mutex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Thief is a class which continually tries to acquire a jar and take a bean * from it. When the jar is empty the thief stops. */ public class Thief extends Thread { + private static final Logger LOGGER = LoggerFactory.getLogger(Thief.class); + /** * The name of the thief. */ @@ -53,10 +58,10 @@ public class Thief extends Thread { while (jar.takeBean()) { beans = beans + 1; - System.out.println(name + " took a bean."); + LOGGER.info("{} took a bean.", name); } - System.out.println(name + " took " + beans + " beans."); + LOGGER.info("{} took {} beans.", name, beans); } } diff --git a/naked-objects/dom/log4j.properties b/naked-objects/dom/log4j.properties deleted file mode 100644 index ca165acc7..000000000 --- a/naked-objects/dom/log4j.properties +++ /dev/null @@ -1,41 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# LOG4J Configuration -# =================== - -# Basic logging goes to "datanucleus.log" -log4j.appender.A1=org.apache.log4j.FileAppender -log4j.appender.A1.File=datanucleus.log -log4j.appender.A1.layout=org.apache.log4j.PatternLayout -log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} (%t) %-5p [%c] - %m%n -#log4j.appender.A1.Threshold=INFO - -# Categories -# Each category can be set to a "level", and to direct to an appender - -# Default to DEBUG level for all DataNucleus categories -log4j.logger.DataNucleus = DEBUG, A1 - -log4j.category.com.mchange.v2.c3p0=INFO, A1 -log4j.category.com.mchange.v2.resourcepool=INFO, A1 -log4j.category.org.logicalcobwebs.proxool=INFO,A1 - - -# Hbase libs logging -log4j.category.org.apache.hadoop=INFO,A1 -log4j.category.org.apache.zookeeper=INFO,A1 \ No newline at end of file diff --git a/naked-objects/integtests/logging.properties b/naked-objects/integtests/logging.properties deleted file mode 100644 index b55249569..000000000 --- a/naked-objects/integtests/logging.properties +++ /dev/null @@ -1,111 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - - -# -# Isis uses log4j is used to provide system logging -# -log4j.rootCategory=INFO, Console - -# The console appender -log4j.appender.Console=org.apache.log4j.ConsoleAppender -log4j.appender.Console.target=System.out -log4j.appender.Console.layout=org.apache.log4j.PatternLayout -log4j.appender.Console.layout.ConversionPattern=%d{ABSOLUTE} [%-20c{1} %-10t %-5p] %m%n - -log4j.appender.File=org.apache.log4j.RollingFileAppender -log4j.appender.File.file=isis.log -log4j.appender.File.append=false -log4j.appender.File.layout=org.apache.log4j.PatternLayout -log4j.appender.File.layout.ConversionPattern=%d [%-20c{1} %-10t %-5p] %m%n - -log4j.appender.translations-po=org.apache.log4j.FileAppender -log4j.appender.translations-po.File=./translations.pot -log4j.appender.translations-po.Append=false -log4j.appender.translations-po.layout=org.apache.log4j.PatternLayout -log4j.appender.translations-po.layout.ConversionPattern=%m%n - -! turn on the internal log4j debugging flag so we can see what it is doing -#log4j.debug=true - - -# DataNucleus -# the first two log the DML and DDL (if set to DEBUG) -log4j.logger.DataNucleus.Datastore.Native=WARN, Console -log4j.logger.DataNucleus.Datastore.Schema=DEBUG, Console -# the remainder can probably be left to WARN -log4j.logger.DataNucleus.Persistence=WARN, Console -log4j.logger.DataNucleus.Transaction=WARN, Console -log4j.logger.DataNucleus.Connection=WARN, Console -log4j.logger.DataNucleus.Query=WARN, Console -log4j.logger.DataNucleus.Cache=WARN, Console -log4j.logger.DataNucleus.MetaData=WARN, Console -log4j.logger.DataNucleus.Datastore=WARN, Console -log4j.logger.DataNucleus.Datastore.Persist=WARN, Console -log4j.logger.DataNucleus.Datastore.Retrieve=WARN, Console -log4j.logger.DataNucleus.General=WARN, Console -log4j.logger.DataNucleus.Lifecycle=WARN, Console -log4j.logger.DataNucleus.ValueGeneration=WARN, Console -log4j.logger.DataNucleus.Enhancer=WARN, Console -log4j.logger.DataNucleus.SchemaTool=ERROR, Console -log4j.logger.DataNucleus.JDO=WARN, Console -log4j.logger.DataNucleus.JPA=ERROR, Console -log4j.logger.DataNucleus.JCA=WARN, Console -log4j.logger.DataNucleus.IDE=ERROR, Console - -log4j.additivity.DataNucleus.Datastore.Native=false -log4j.additivity.DataNucleus.Datastore.Schema=false -log4j.additivity.DataNucleus.Datastore.Persistence=false -log4j.additivity.DataNucleus.Datastore.Transaction=false -log4j.additivity.DataNucleus.Datastore.Connection=false -log4j.additivity.DataNucleus.Datastore.Query=false -log4j.additivity.DataNucleus.Datastore.Cache=false -log4j.additivity.DataNucleus.Datastore.MetaData=false -log4j.additivity.DataNucleus.Datastore.Datastore=false -log4j.additivity.DataNucleus.Datastore.Datastore.Persist=false -log4j.additivity.DataNucleus.Datastore.Datastore.Retrieve=false -log4j.additivity.DataNucleus.Datastore.General=false -log4j.additivity.DataNucleus.Datastore.Lifecycle=false -log4j.additivity.DataNucleus.Datastore.ValueGeneration=false -log4j.additivity.DataNucleus.Datastore.Enhancer=false -log4j.additivity.DataNucleus.Datastore.SchemaTool=false -log4j.additivity.DataNucleus.Datastore.JDO=false -log4j.additivity.DataNucleus.Datastore.JPA=false -log4j.additivity.DataNucleus.Datastore.JCA=false -log4j.additivity.DataNucleus.Datastore.IDE=false - - - - -# if using log4jdbc-remix as JDBC driver -#log4j.logger.jdbc.sqlonly=DEBUG, sql, Console -#log4j.additivity.jdbc.sqlonly=false -#log4j.logger.jdbc.resultsettable=DEBUG, jdbc, Console -#log4j.additivity.jdbc.resultsettable=false - -#log4j.logger.jdbc.audit=WARN,jdbc, Console -#log4j.additivity.jdbc.audit=false -#log4j.logger.jdbc.resultset=WARN,jdbc -#log4j.additivity.jdbc.resultset=false -#log4j.logger.jdbc.sqltiming=WARN,sqltiming -#log4j.additivity.jdbc.sqltiming=false -#log4j.logger.jdbc.connection=FATAL,connection -#log4j.additivity.jdbc.connection=false - - -log4j.logger.org.apache.isis.core.runtime.services.i18n.po.PoWriter=INFO,translations-po -log4j.additivity.org.apache.isis.core.runtime.services.i18n.po.PotWriter=false diff --git a/naked-objects/webapp/src/main/webapp/WEB-INF/logging.properties b/naked-objects/webapp/src/main/webapp/WEB-INF/logging.properties deleted file mode 100644 index 62fd8ea5e..000000000 --- a/naked-objects/webapp/src/main/webapp/WEB-INF/logging.properties +++ /dev/null @@ -1,187 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - - -# -# Isis uses log4j is used to provide system logging -# -log4j.rootCategory=INFO, Console -#log4j.rootCategory=DEBUG, Console - - -# The console appender -log4j.appender.Console=org.apache.log4j.ConsoleAppender -log4j.appender.Console.target=System.out -log4j.appender.Console.layout=org.apache.log4j.PatternLayout -log4j.appender.Console.layout.ConversionPattern=%d{ABSOLUTE} [%-20c{1} %-10t %-5p] %m%n - - -# The stderr appender -log4j.appender.Stderr=org.apache.log4j.ConsoleAppender -log4j.appender.Stderr.target=System.err -log4j.appender.Stderr.layout=org.apache.log4j.PatternLayout -log4j.appender.Stderr.layout.ConversionPattern=%d{ABSOLUTE} [%-20c{1} %-10t %-5p] %m%n - - -# other appenders -log4j.appender.File=org.apache.log4j.RollingFileAppender -log4j.appender.File.file=isis.log -log4j.appender.File.append=false -log4j.appender.File.layout=org.apache.log4j.PatternLayout -log4j.appender.File.layout.ConversionPattern=%d [%-20c{1} %-10t %-5p] %m%n - -log4j.appender.sql=org.apache.log4j.FileAppender -log4j.appender.sql.File=./logs/sql.log -log4j.appender.sql.Append=false -log4j.appender.sql.layout=org.apache.log4j.PatternLayout -log4j.appender.sql.layout.ConversionPattern=-----> %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n%n - -log4j.appender.sqltiming=org.apache.log4j.FileAppender -log4j.appender.sqltiming.File=./logs/sqltiming.log -log4j.appender.sqltiming.Append=false -log4j.appender.sqltiming.layout=org.apache.log4j.PatternLayout -log4j.appender.sqltiming.layout.ConversionPattern=-----> %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n%n - -log4j.appender.jdbc=org.apache.log4j.FileAppender -log4j.appender.jdbc.File=./logs/jdbc.log -log4j.appender.jdbc.Append=false -log4j.appender.jdbc.layout=org.apache.log4j.PatternLayout -log4j.appender.jdbc.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n - -log4j.appender.connection=org.apache.log4j.FileAppender -log4j.appender.connection.File=./logs/connection.log -log4j.appender.connection.Append=false -log4j.appender.connection.layout=org.apache.log4j.PatternLayout -log4j.appender.connection.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n - - - - -! turn on the internal log4j debugging flag so we can see what it is doing -#log4j.debug=true - - -# DataNucleus -# the first two log the DML and DDL (if set to DEBUG) -log4j.logger.DataNucleus.Datastore.Native=WARN, Console -log4j.logger.DataNucleus.Datastore.Schema=DEBUG, Console -# the remainder can probably be left to WARN -log4j.logger.DataNucleus.Persistence=WARN, Console -log4j.logger.DataNucleus.Transaction=WARN, Console -log4j.logger.DataNucleus.Connection=WARN, Console -log4j.logger.DataNucleus.Query=WARN, Console -log4j.logger.DataNucleus.Cache=WARN, Console -log4j.logger.DataNucleus.MetaData=WARN, Console -log4j.logger.DataNucleus.Datastore=WARN, Console -log4j.logger.DataNucleus.Datastore.Persist=WARN, Console -log4j.logger.DataNucleus.Datastore.Retrieve=WARN, Console -log4j.logger.DataNucleus.General=WARN, Console -log4j.logger.DataNucleus.Lifecycle=WARN, Console -log4j.logger.DataNucleus.ValueGeneration=WARN, Console -log4j.logger.DataNucleus.Enhancer=WARN, Console -log4j.logger.DataNucleus.SchemaTool=ERROR, Console -log4j.logger.DataNucleus.JDO=WARN, Console -log4j.logger.DataNucleus.JPA=ERROR, Console -log4j.logger.DataNucleus.JCA=WARN, Console -log4j.logger.DataNucleus.IDE=ERROR, Console - -log4j.additivity.DataNucleus.Datastore.Native=false -log4j.additivity.DataNucleus.Datastore.Schema=false -log4j.additivity.DataNucleus.Datastore.Persistence=false -log4j.additivity.DataNucleus.Datastore.Transaction=false -log4j.additivity.DataNucleus.Datastore.Connection=false -log4j.additivity.DataNucleus.Datastore.Query=false -log4j.additivity.DataNucleus.Datastore.Cache=false -log4j.additivity.DataNucleus.Datastore.MetaData=false -log4j.additivity.DataNucleus.Datastore.Datastore=false -log4j.additivity.DataNucleus.Datastore.Datastore.Persist=false -log4j.additivity.DataNucleus.Datastore.Datastore.Retrieve=false -log4j.additivity.DataNucleus.Datastore.General=false -log4j.additivity.DataNucleus.Datastore.Lifecycle=false -log4j.additivity.DataNucleus.Datastore.ValueGeneration=false -log4j.additivity.DataNucleus.Datastore.Enhancer=false -log4j.additivity.DataNucleus.Datastore.SchemaTool=false -log4j.additivity.DataNucleus.Datastore.JDO=false -log4j.additivity.DataNucleus.Datastore.JPA=false -log4j.additivity.DataNucleus.Datastore.JCA=false -log4j.additivity.DataNucleus.Datastore.IDE=false - - -# if using log4jdbc-remix as JDBC driver -#log4j.logger.jdbc.sqlonly=DEBUG, sql, Console -#log4j.additivity.jdbc.sqlonly=false -#log4j.logger.jdbc.resultsettable=DEBUG, jdbc, Console -#log4j.additivity.jdbc.resultsettable=false - -#log4j.logger.jdbc.audit=WARN,jdbc, Console -#log4j.additivity.jdbc.audit=false -#log4j.logger.jdbc.resultset=WARN,jdbc -#log4j.additivity.jdbc.resultset=false -#log4j.logger.jdbc.sqltiming=WARN,sqltiming -#log4j.additivity.jdbc.sqltiming=false -#log4j.logger.jdbc.connection=FATAL,connection -#log4j.additivity.jdbc.connection=false - - - -# track Isis/JDO lifecycle integration - -#log4j.logger.org.apache.isis.runtimes.dflt.objectstores.jdo.datanucleus.persistence.FrameworkSynchronizer=DEBUG, Console -#log4j.additivity.org.apache.isis.runtimes.dflt.objectstores.jdo.datanucleus.persistence.FrameworkSynchronizer=false - -#log4j.logger.org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener=DEBUG,Console -#log4j.additivity.org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener=false - - - - -# track Isis/Wicket lifecycle integration - -#log4j.logger.org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleForIsis=DEBUG, Console -#log4j.additivity.org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleForIsis=false - -#log4j.logger.org.apache.isis.viewer.wicket.viewer.integration.isis.IsisContextForWicket=INFO,Console -#log4j.additivity.org.apache.isis.viewer.wicket.viewer.integration.isis.IsisContextForWicket=false - - - - -# quieten some of the noisier classes in Isis' bootstrapping -log4j.logger.org.apache.isis.core.metamodel.specloader.specimpl.FacetedMethodsBuilder=WARN,Console -log4j.additivity.org.apache.isis.core.metamodel.specloader.specimpl.FacetedMethodsBuilder=false - -log4j.logger.org.apache.isis.core.metamodel.specloader.ServiceInitializer=WARN,Console -log4j.additivity.org.apache.isis.core.metamodel.specloader.ServiceInitializer=false - -log4j.logger.org.apache.isis.core.runtime.services.ServicesInstallerFromConfiguration=WARN,Console -log4j.additivity.org.apache.isis.core.runtime.services.ServicesInstallerFromConfiguration=false - -log4j.logger.org.apache.isis.core.commons.config.IsisConfigurationDefault=WARN,Console -log4j.additivity.org.apache.isis.core.commons.config.IsisConfigurationDefault=false - -log4j.logger.org.apache.isis.core.runtime.installers.InstallerLookupDefault=WARN,Console -log4j.additivity.org.apache.isis.core.runtime.installers.InstallerLookupDefault=false - - -# quieten Shiro -log4j.logger.org.apache.shiro.realm.AuthorizingRealm=WARN,Console -log4j.additivity.log4j.logger.org.apache.shiro.realm.AuthorizingRealm=false - - -# Application-specific logging -log4j.logger.dom.simple.SimpleObject=DEBUG, Stderr -log4j.additivity.dom.simple.SimpleObject=false \ No newline at end of file diff --git a/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java b/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java index 46787ac96..c2fd66849 100644 --- a/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java +++ b/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java @@ -22,6 +22,9 @@ */ package com.iluwatar.nullobject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Implementation for binary tree's normal nodes. @@ -29,6 +32,8 @@ package com.iluwatar.nullobject; */ public class NodeImpl implements Node { + private static final Logger LOGGER = LoggerFactory.getLogger(NodeImpl.class); + private final String name; private final Node left; private final Node right; @@ -64,7 +69,7 @@ public class NodeImpl implements Node { @Override public void walk() { - System.out.println(name); + LOGGER.info(name); if (left.getTreeSize() > 0) { left.walk(); } diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/App.java b/object-pool/src/main/java/com/iluwatar/object/pool/App.java index 66b3e3f90..b49dd70d7 100644 --- a/object-pool/src/main/java/com/iluwatar/object/pool/App.java +++ b/object-pool/src/main/java/com/iluwatar/object/pool/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.object.pool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * When it is necessary to work with a large number of objects that are particularly expensive to @@ -44,6 +47,8 @@ package com.iluwatar.object.pool; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -51,24 +56,24 @@ public class App { */ public static void main(String[] args) { OliphauntPool pool = new OliphauntPool(); - System.out.println(pool); + LOGGER.info(pool.toString()); Oliphaunt oliphaunt1 = pool.checkOut(); - System.out.println("Checked out " + oliphaunt1); - System.out.println(pool); + LOGGER.info("Checked out {}", oliphaunt1); + LOGGER.info(pool.toString()); Oliphaunt oliphaunt2 = pool.checkOut(); - System.out.println("Checked out " + oliphaunt2); + LOGGER.info("Checked out {}", oliphaunt2); Oliphaunt oliphaunt3 = pool.checkOut(); - System.out.println("Checked out " + oliphaunt3); - System.out.println(pool); - System.out.println("Checking in " + oliphaunt1); + LOGGER.info("Checked out {}", oliphaunt3); + LOGGER.info(pool.toString()); + LOGGER.info("Checking in {}", oliphaunt1); pool.checkIn(oliphaunt1); - System.out.println("Checking in " + oliphaunt2); + LOGGER.info("Checking in {}", oliphaunt2); pool.checkIn(oliphaunt2); - System.out.println(pool); + LOGGER.info(pool.toString()); Oliphaunt oliphaunt4 = pool.checkOut(); - System.out.println("Checked out " + oliphaunt4); + LOGGER.info("Checked out {}", oliphaunt4); Oliphaunt oliphaunt5 = pool.checkOut(); - System.out.println("Checked out " + oliphaunt5); - System.out.println(pool); + LOGGER.info("Checked out {}", oliphaunt5); + LOGGER.info(pool.toString()); } } diff --git a/observer/src/main/java/com/iluwatar/observer/App.java b/observer/src/main/java/com/iluwatar/observer/App.java index dcced00d4..d6a8e0df6 100644 --- a/observer/src/main/java/com/iluwatar/observer/App.java +++ b/observer/src/main/java/com/iluwatar/observer/App.java @@ -25,6 +25,8 @@ package com.iluwatar.observer; import com.iluwatar.observer.generic.GHobbits; import com.iluwatar.observer.generic.GOrcs; import com.iluwatar.observer.generic.GWeather; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -41,6 +43,8 @@ import com.iluwatar.observer.generic.GWeather; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -58,7 +62,7 @@ public class App { weather.timePasses(); // Generic observer inspired by Java Generics and Collection by Naftalin & Wadler - System.out.println("\n--Running generic version--"); + LOGGER.info("--Running generic version--"); GWeather gWeather = new GWeather(); gWeather.addObserver(new GOrcs()); gWeather.addObserver(new GHobbits()); diff --git a/observer/src/main/java/com/iluwatar/observer/Hobbits.java b/observer/src/main/java/com/iluwatar/observer/Hobbits.java index ed9636bd6..74ffee713 100644 --- a/observer/src/main/java/com/iluwatar/observer/Hobbits.java +++ b/observer/src/main/java/com/iluwatar/observer/Hobbits.java @@ -22,6 +22,9 @@ */ package com.iluwatar.observer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Hobbits @@ -29,20 +32,22 @@ package com.iluwatar.observer; */ public class Hobbits implements WeatherObserver { + private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class); + @Override public void update(WeatherType currentWeather) { switch (currentWeather) { case COLD: - System.out.println("The hobbits are shivering in the cold weather."); + LOGGER.info("The hobbits are shivering in the cold weather."); break; case RAINY: - System.out.println("The hobbits look for cover from the rain."); + LOGGER.info("The hobbits look for cover from the rain."); break; case SUNNY: - System.out.println("The happy hobbits bade in the warm sun."); + LOGGER.info("The happy hobbits bade in the warm sun."); break; case WINDY: - System.out.println("The hobbits hold their hats tightly in the windy weather."); + LOGGER.info("The hobbits hold their hats tightly in the windy weather."); break; default: break; diff --git a/observer/src/main/java/com/iluwatar/observer/Orcs.java b/observer/src/main/java/com/iluwatar/observer/Orcs.java index ce9c09944..65ddc840f 100644 --- a/observer/src/main/java/com/iluwatar/observer/Orcs.java +++ b/observer/src/main/java/com/iluwatar/observer/Orcs.java @@ -22,6 +22,9 @@ */ package com.iluwatar.observer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Orcs @@ -29,20 +32,22 @@ package com.iluwatar.observer; */ public class Orcs implements WeatherObserver { + private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class); + @Override public void update(WeatherType currentWeather) { switch (currentWeather) { case COLD: - System.out.println("The orcs are freezing cold."); + LOGGER.info("The orcs are freezing cold."); break; case RAINY: - System.out.println("The orcs are dripping wet."); + LOGGER.info("The orcs are dripping wet."); break; case SUNNY: - System.out.println("The sun hurts the orcs' eyes."); + LOGGER.info("The sun hurts the orcs' eyes."); break; case WINDY: - System.out.println("The orc smell almost vanishes in the wind."); + LOGGER.info("The orc smell almost vanishes in the wind."); break; default: break; diff --git a/observer/src/main/java/com/iluwatar/observer/Weather.java b/observer/src/main/java/com/iluwatar/observer/Weather.java index f6aad3881..c89ffd366 100644 --- a/observer/src/main/java/com/iluwatar/observer/Weather.java +++ b/observer/src/main/java/com/iluwatar/observer/Weather.java @@ -22,6 +22,9 @@ */ package com.iluwatar.observer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.List; @@ -33,6 +36,8 @@ import java.util.List; */ public class Weather { + private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class); + private WeatherType currentWeather; private List observers; @@ -55,7 +60,7 @@ public class Weather { public void timePasses() { WeatherType[] enumValues = WeatherType.values(); currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; - System.out.println("The weather changed to " + currentWeather + "."); + LOGGER.info("The weather changed to {}.", currentWeather); notifyObservers(); } diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java b/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java index da84b9aab..f70a1a62e 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java @@ -23,6 +23,8 @@ package com.iluwatar.observer.generic; import com.iluwatar.observer.WeatherType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -30,20 +32,23 @@ import com.iluwatar.observer.WeatherType; * */ public class GHobbits implements Race { + + private static final Logger LOGGER = LoggerFactory.getLogger(GHobbits.class); + @Override public void update(GWeather weather, WeatherType weatherType) { switch (weatherType) { case COLD: - System.out.println("The hobbits are shivering in the cold weather."); + LOGGER.info("The hobbits are shivering in the cold weather."); break; case RAINY: - System.out.println("The hobbits look for cover from the rain."); + LOGGER.info("The hobbits look for cover from the rain."); break; case SUNNY: - System.out.println("The happy hobbits bade in the warm sun."); + LOGGER.info("The happy hobbits bade in the warm sun."); break; case WINDY: - System.out.println("The hobbits hold their hats tightly in the windy weather."); + LOGGER.info("The hobbits hold their hats tightly in the windy weather."); break; default: break; diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java b/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java index 9f41aa6cc..3171f4e7c 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java @@ -23,6 +23,8 @@ package com.iluwatar.observer.generic; import com.iluwatar.observer.WeatherType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -31,20 +33,22 @@ import com.iluwatar.observer.WeatherType; */ public class GOrcs implements Race { + private static final Logger LOGGER = LoggerFactory.getLogger(GOrcs.class); + @Override public void update(GWeather weather, WeatherType weatherType) { switch (weatherType) { case COLD: - System.out.println("The orcs are freezing cold."); + LOGGER.info("The orcs are freezing cold."); break; case RAINY: - System.out.println("The orcs are dripping wet."); + LOGGER.info("The orcs are dripping wet."); break; case SUNNY: - System.out.println("The sun hurts the orcs' eyes."); + LOGGER.info("The sun hurts the orcs' eyes."); break; case WINDY: - System.out.println("The orc smell almost vanishes in the wind."); + LOGGER.info("The orc smell almost vanishes in the wind."); break; default: break; diff --git a/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java b/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java index 137000760..631da479e 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/GWeather.java @@ -23,6 +23,8 @@ package com.iluwatar.observer.generic; import com.iluwatar.observer.WeatherType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -31,6 +33,8 @@ import com.iluwatar.observer.WeatherType; */ public class GWeather extends Observable { + private static final Logger LOGGER = LoggerFactory.getLogger(GWeather.class); + private WeatherType currentWeather; public GWeather() { @@ -43,7 +47,7 @@ public class GWeather extends Observable { public void timePasses() { WeatherType[] enumValues = WeatherType.values(); currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; - System.out.println("The weather changed to " + currentWeather + "."); + LOGGER.info("The weather changed to {}.", currentWeather); notifyObservers(currentWeather); } } diff --git a/poison-pill/src/main/java/com/iluwatar/poison/pill/Consumer.java b/poison-pill/src/main/java/com/iluwatar/poison/pill/Consumer.java index c811225e1..6a586c52d 100644 --- a/poison-pill/src/main/java/com/iluwatar/poison/pill/Consumer.java +++ b/poison-pill/src/main/java/com/iluwatar/poison/pill/Consumer.java @@ -23,11 +23,15 @@ package com.iluwatar.poison.pill; import com.iluwatar.poison.pill.Message.Headers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Class responsible for receiving and handling submitted to the queue messages */ public class Consumer { + + private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class); private final MqSubscribePoint queue; private final String name; @@ -46,19 +50,18 @@ public class Consumer { try { msg = queue.take(); if (Message.POISON_PILL.equals(msg)) { - System.out.println(String.format("Consumer %s receive request to terminate.", name)); + LOGGER.info("Consumer {} receive request to terminate.", name); break; } } catch (InterruptedException e) { // allow thread to exit - System.err.println(e); + LOGGER.error("Exception caught.", e); return; } String sender = msg.getHeader(Headers.SENDER); String body = msg.getBody(); - System.out.println(String.format("Message [%s] from [%s] received by [%s]", body, sender, - name)); + LOGGER.info("Message [{}] from [{}] received by [{}]", body, sender, name); } } } diff --git a/poison-pill/src/main/java/com/iluwatar/poison/pill/Producer.java b/poison-pill/src/main/java/com/iluwatar/poison/pill/Producer.java index 15dcad40e..af07ed679 100644 --- a/poison-pill/src/main/java/com/iluwatar/poison/pill/Producer.java +++ b/poison-pill/src/main/java/com/iluwatar/poison/pill/Producer.java @@ -25,6 +25,8 @@ package com.iluwatar.poison.pill; import java.util.Date; import com.iluwatar.poison.pill.Message.Headers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Class responsible for producing unit of work that can be expressed as message and submitted to @@ -32,6 +34,8 @@ import com.iluwatar.poison.pill.Message.Headers; */ public class Producer { + private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class); + private final MqPublishPoint queue; private final String name; private boolean isStopped; @@ -62,7 +66,7 @@ public class Producer { queue.put(msg); } catch (InterruptedException e) { // allow thread to exit - System.err.println(e); + LOGGER.error("Exception caught.", e); } } @@ -75,7 +79,7 @@ public class Producer { queue.put(Message.POISON_PILL); } catch (InterruptedException e) { // allow thread to exit - System.err.println(e); + LOGGER.error("Exception caught.", e); } } } diff --git a/pom.xml b/pom.xml index 144b8efff..d4d7ff581 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,6 @@ 0.7.2.201409121644 1.4 2.16.1 - 1.2.17 19.0 1.15.1 1.10.19 @@ -49,6 +48,8 @@ 1.4.1 4.0 3.3.0 + 1.7.21 + 1.1.7 abstract-factory @@ -210,11 +211,6 @@ ${mockito.version} test - - log4j - log4j - ${log4j.version} - com.google.guava guava @@ -251,6 +247,23 @@ + + + org.slf4j + slf4j-api + ${slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + ch.qos.logback + logback-core + ${logback.version} + + diff --git a/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java b/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java index b9d2ad09c..73bfb948f 100644 --- a/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java +++ b/private-class-data/src/main/java/com/iluwatar/privateclassdata/ImmutableStew.java @@ -22,6 +22,9 @@ */ package com.iluwatar.privateclassdata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Immutable stew class, protected with Private Class Data pattern @@ -29,6 +32,8 @@ package com.iluwatar.privateclassdata; */ public class ImmutableStew { + private static final Logger LOGGER = LoggerFactory.getLogger(ImmutableStew.class); + private StewData data; public ImmutableStew(int numPotatoes, int numCarrots, int numMeat, int numPeppers) { @@ -39,8 +44,7 @@ public class ImmutableStew { * Mix the stew */ public void mix() { - System.out.println(String.format( - "Mixing the immutable stew we find: %d potatoes, %d carrots, %d meat and %d peppers", - data.getNumPotatoes(), data.getNumCarrots(), data.getNumMeat(), data.getNumPeppers())); + LOGGER.info("Mixing the immutable stew we find: {} potatoes, {} carrots, {} meat and {} peppers", + data.getNumPotatoes(), data.getNumCarrots(), data.getNumMeat(), data.getNumPeppers()); } } diff --git a/private-class-data/src/main/java/com/iluwatar/privateclassdata/Stew.java b/private-class-data/src/main/java/com/iluwatar/privateclassdata/Stew.java index 9c9033018..665edf418 100644 --- a/private-class-data/src/main/java/com/iluwatar/privateclassdata/Stew.java +++ b/private-class-data/src/main/java/com/iluwatar/privateclassdata/Stew.java @@ -22,6 +22,9 @@ */ package com.iluwatar.privateclassdata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Mutable stew class @@ -29,6 +32,8 @@ package com.iluwatar.privateclassdata; */ public class Stew { + private static final Logger LOGGER = LoggerFactory.getLogger(Stew.class); + private int numPotatoes; private int numCarrots; private int numMeat; @@ -48,16 +53,15 @@ public class Stew { * Mix the stew */ public void mix() { - System.out.println(String.format( - "Mixing the stew we find: %d potatoes, %d carrots, %d meat and %d peppers", numPotatoes, - numCarrots, numMeat, numPeppers)); + LOGGER.info("Mixing the stew we find: {} potatoes, {} carrots, {} meat and {} peppers", + numPotatoes, numCarrots, numMeat, numPeppers); } /** * Taste the stew */ public void taste() { - System.out.println("Tasting the stew"); + LOGGER.info("Tasting the stew"); if (numPotatoes > 0) { numPotatoes--; } diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java index 42f6dfa79..dca2457c4 100644 --- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.producer.consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -37,6 +40,8 @@ import java.util.concurrent.TimeUnit; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -72,7 +77,7 @@ public class App { executorService.awaitTermination(10, TimeUnit.SECONDS); executorService.shutdownNow(); } catch (InterruptedException e) { - System.out.println("Error waiting for ExecutorService shutdown"); + LOGGER.error("Error waiting for ExecutorService shutdown"); } } } diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java index f1fa920f3..880b76ba5 100644 --- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java @@ -22,11 +22,16 @@ */ package com.iluwatar.producer.consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Class responsible for consume the {@link Item} produced by {@link Producer} */ public class Consumer { + private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class); + private final ItemQueue queue; private final String name; @@ -42,8 +47,7 @@ public class Consumer { public void consume() throws InterruptedException { Item item = queue.take(); - System.out.println(String.format("Consumer [%s] consume item [%s] produced by [%s]", name, - item.getId(), item.getProducer())); + LOGGER.info("Consumer [{}] consume item [{}] produced by [{}]", name, item.getId(), item.getProducer()); } } diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 672c20bfa..7e1f174ef 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -21,6 +21,9 @@ * THE SOFTWARE. */ package com.iluwatar.promise; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; @@ -60,6 +63,8 @@ import java.util.concurrent.Executors; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private static final String DEFAULT_URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; private final ExecutorService executor; private final CountDownLatch stopLatch; @@ -98,7 +103,7 @@ public class App { lowestFrequencyChar() .thenAccept( charFrequency -> { - System.out.println("Char with lowest frequency is: " + charFrequency); + LOGGER.info("Char with lowest frequency is: {}", charFrequency); taskCompleted(); } ); @@ -112,7 +117,7 @@ public class App { countLines() .thenAccept( count -> { - System.out.println("Line count is: " + count); + LOGGER.info("Line count is: {}", count); taskCompleted(); } ); diff --git a/promise/src/main/java/com/iluwatar/promise/Utility.java b/promise/src/main/java/com/iluwatar/promise/Utility.java index d451600a3..769a6fcd1 100644 --- a/promise/src/main/java/com/iluwatar/promise/Utility.java +++ b/promise/src/main/java/com/iluwatar/promise/Utility.java @@ -22,6 +22,9 @@ */ package com.iluwatar.promise; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -38,6 +41,8 @@ import java.util.Map.Entry; public class Utility { + private static final Logger LOGGER = LoggerFactory.getLogger(Utility.class); + /** * Calculates character frequency of the file provided. * @param fileLocation location of the file. @@ -104,7 +109,7 @@ public class Utility { * @return the absolute path of the file downloaded. */ public static String downloadFile(String urlString) throws MalformedURLException, IOException { - System.out.println("Downloading contents from url: " + urlString); + LOGGER.info("Downloading contents from url: {}", urlString); URL url = new URL(urlString); File file = File.createTempFile("promise_pattern", null); try (Reader reader = new InputStreamReader(url.openStream()); @@ -114,7 +119,7 @@ public class Utility { writer.write(line); writer.write("\n"); } - System.out.println("File downloaded at: " + file.getAbsolutePath()); + LOGGER.info("File downloaded at: {}", file.getAbsolutePath()); return file.getAbsolutePath(); } catch (IOException ex) { throw ex; diff --git a/property/src/main/java/com/iluwatar/property/App.java b/property/src/main/java/com/iluwatar/property/App.java index e3f7cc92b..576bada18 100644 --- a/property/src/main/java/com/iluwatar/property/App.java +++ b/property/src/main/java/com/iluwatar/property/App.java @@ -23,6 +23,8 @@ package com.iluwatar.property; import com.iluwatar.property.Character.Type; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -39,6 +41,8 @@ import com.iluwatar.property.Character.Type; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -67,16 +71,16 @@ public class App { /* usage */ Character mag = new Character("Player_1", mageProto); mag.set(Stats.ARMOR, 8); - System.out.println(mag); + LOGGER.info(mag.toString()); Character warrior = new Character("Player_2", warProto); - System.out.println(warrior); + LOGGER.info(warrior.toString()); Character rogue = new Character("Player_3", rogueProto); - System.out.println(rogue); + LOGGER.info(rogue.toString()); Character rogueDouble = new Character("Player_4", rogue); rogueDouble.set(Stats.ATTACK_POWER, 12); - System.out.println(rogueDouble); + LOGGER.info(rogueDouble.toString()); } } diff --git a/prototype/src/main/java/com/iluwatar/prototype/App.java b/prototype/src/main/java/com/iluwatar/prototype/App.java index cb04ec5f2..bb98194ce 100644 --- a/prototype/src/main/java/com/iluwatar/prototype/App.java +++ b/prototype/src/main/java/com/iluwatar/prototype/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.prototype; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Prototype pattern is a creational design pattern in software development. It is used when the @@ -36,6 +39,8 @@ package com.iluwatar.prototype; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -51,16 +56,16 @@ public class App { mage = factory.createMage(); warlord = factory.createWarlord(); beast = factory.createBeast(); - System.out.println(mage); - System.out.println(warlord); - System.out.println(beast); + LOGGER.info(mage.toString()); + LOGGER.info(warlord.toString()); + LOGGER.info(beast.toString()); factory = new HeroFactoryImpl(new OrcMage(), new OrcWarlord(), new OrcBeast()); mage = factory.createMage(); warlord = factory.createWarlord(); beast = factory.createBeast(); - System.out.println(mage); - System.out.println(warlord); - System.out.println(beast); + LOGGER.info(mage.toString()); + LOGGER.info(warlord.toString()); + LOGGER.info(beast.toString()); } } diff --git a/proxy/src/main/java/com/iluwatar/proxy/WizardTower.java b/proxy/src/main/java/com/iluwatar/proxy/WizardTower.java index 573d38374..d5daab305 100644 --- a/proxy/src/main/java/com/iluwatar/proxy/WizardTower.java +++ b/proxy/src/main/java/com/iluwatar/proxy/WizardTower.java @@ -22,6 +22,9 @@ */ package com.iluwatar.proxy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The object to be proxyed. @@ -29,8 +32,10 @@ package com.iluwatar.proxy; */ public class WizardTower { + private static final Logger LOGGER = LoggerFactory.getLogger(WizardTower.class); + public void enter(Wizard wizard) { - System.out.println(wizard + " enters the tower."); + LOGGER.info("{} enters the tower.", wizard); } } diff --git a/proxy/src/main/java/com/iluwatar/proxy/WizardTowerProxy.java b/proxy/src/main/java/com/iluwatar/proxy/WizardTowerProxy.java index 985184afe..1048724d4 100644 --- a/proxy/src/main/java/com/iluwatar/proxy/WizardTowerProxy.java +++ b/proxy/src/main/java/com/iluwatar/proxy/WizardTowerProxy.java @@ -22,6 +22,9 @@ */ package com.iluwatar.proxy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The proxy controlling access to the {@link WizardTower}. @@ -29,6 +32,8 @@ package com.iluwatar.proxy; */ public class WizardTowerProxy extends WizardTower { + private static final Logger LOGGER = LoggerFactory.getLogger(WizardTowerProxy.class); + private static final int NUM_WIZARDS_ALLOWED = 3; private int numWizards; @@ -39,7 +44,7 @@ public class WizardTowerProxy extends WizardTower { super.enter(wizard); numWizards++; } else { - System.out.println(wizard + " is not allowed to enter!"); + LOGGER.info("{} is not allowed to enter!", wizard); } } } diff --git a/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java b/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java index c4e423b04..ff66e4e58 100644 --- a/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java +++ b/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java @@ -26,6 +26,8 @@ import org.apache.camel.CamelContext; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultCamelContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -48,6 +50,8 @@ import org.apache.camel.impl.DefaultCamelContext; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ @@ -61,7 +65,7 @@ public class App { }); ProducerTemplate template = context.createProducerTemplate(); context.start(); - context.getRoutes().stream().forEach(r -> System.out.println(r)); + context.getRoutes().stream().forEach(r -> LOGGER.info(r.toString())); template.sendBody("direct:origin", "Hello from origin"); context.stop(); } diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java index 29c2f83fa..77e4e1f4f 100644 --- a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java +++ b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java @@ -22,6 +22,9 @@ */ package com.iluwatar.reactor.app; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -41,6 +44,9 @@ import java.util.concurrent.TimeUnit; * requests to Reactor. */ public class AppClient { + + private static final Logger LOGGER = LoggerFactory.getLogger(AppClient.class); + private final ExecutorService service = Executors.newFixedThreadPool(4); /** @@ -126,9 +132,9 @@ public class AppClient { byte[] data = new byte[1024]; int read = inputStream.read(data, 0, data.length); if (read == 0) { - System.out.println("Read zero bytes"); + LOGGER.info("Read zero bytes"); } else { - System.out.println(new String(data, 0, read)); + LOGGER.info(new String(data, 0, read)); } artificialDelayOf(100); @@ -171,9 +177,9 @@ public class AppClient { DatagramPacket reply = new DatagramPacket(data, data.length); socket.receive(reply); if (reply.getLength() == 0) { - System.out.println("Read zero bytes"); + LOGGER.info("Read zero bytes"); } else { - System.out.println(new String(reply.getData(), 0, reply.getLength())); + LOGGER.info(new String(reply.getData(), 0, reply.getLength())); } artificialDelayOf(100); diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java b/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java index ab2bcfb1a..e1095d34e 100644 --- a/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java +++ b/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java @@ -28,6 +28,8 @@ import java.nio.channels.SelectionKey; import com.iluwatar.reactor.framework.AbstractNioChannel; import com.iluwatar.reactor.framework.ChannelHandler; import com.iluwatar.reactor.framework.NioDatagramChannel.DatagramPacket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Logging server application logic. It logs the incoming requests on standard console and returns a @@ -35,6 +37,8 @@ import com.iluwatar.reactor.framework.NioDatagramChannel.DatagramPacket; */ public class LoggingHandler implements ChannelHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(LoggingHandler.class); + private static final byte[] ACK = "Data logged successfully".getBytes(); /** @@ -76,6 +80,6 @@ public class LoggingHandler implements ChannelHandler { private static void doLogging(ByteBuffer data) { // assuming UTF-8 :( - System.out.println(new String(data.array(), 0, data.limit())); + LOGGER.info(new String(data.array(), 0, data.limit())); } } diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java index 4e493163f..52d2d68b0 100644 --- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java @@ -22,6 +22,9 @@ */ package com.iluwatar.reactor.framework; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -35,6 +38,8 @@ import java.nio.channels.SelectionKey; */ public class NioDatagramChannel extends AbstractNioChannel { + private static final Logger LOGGER = LoggerFactory.getLogger(NioDatagramChannel.class); + private final int port; /** @@ -99,7 +104,7 @@ public class NioDatagramChannel extends AbstractNioChannel { public void bind() throws IOException { getJavaChannel().socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), port)); getJavaChannel().configureBlocking(false); - System.out.println("Bound UDP socket at port: " + port); + LOGGER.info("Bound UDP socket at port: {}", port); } /** diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java index 3d5ebf5a0..0facf1935 100644 --- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java @@ -22,6 +22,9 @@ */ package com.iluwatar.reactor.framework; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; @@ -53,6 +56,8 @@ import java.util.concurrent.TimeUnit; */ public class NioReactor { + private static final Logger LOGGER = LoggerFactory.getLogger(NioReactor.class); + private final Selector selector; private final Dispatcher dispatcher; /** @@ -86,7 +91,7 @@ public class NioReactor { public void start() throws IOException { reactorMain.execute(() -> { try { - System.out.println("Reactor started, waiting for events..."); + LOGGER.info("Reactor started, waiting for events..."); eventLoop(); } catch (IOException e) { e.printStackTrace(); diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java index c7d67fd13..d1c6bb62a 100644 --- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java @@ -22,6 +22,9 @@ */ package com.iluwatar.reactor.framework; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -36,6 +39,8 @@ import java.nio.channels.SocketChannel; */ public class NioServerSocketChannel extends AbstractNioChannel { + private static final Logger LOGGER = LoggerFactory.getLogger(NioServerSocketChannel.class); + private final int port; /** @@ -96,7 +101,7 @@ public class NioServerSocketChannel extends AbstractNioChannel { ((ServerSocketChannel) getJavaChannel()).socket().bind( new InetSocketAddress(InetAddress.getLocalHost(), port)); ((ServerSocketChannel) getJavaChannel()).configureBlocking(false); - System.out.println("Bound TCP socket at port: " + port); + LOGGER.info("Bound TCP socket at port: {}", port); } /** 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 index fd5d28ed5..90f7d5e59 100644 --- 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 @@ -23,6 +23,9 @@ package com.iluwatar.reader.writer.lock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -48,6 +51,8 @@ import java.util.stream.IntStream; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -71,7 +76,7 @@ public class App { try { executeService.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.out.println("Error waiting for ExecutorService shutdown"); + LOGGER.error("Error waiting for ExecutorService shutdown"); } } 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 index 2b837b341..644772bf1 100644 --- 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 @@ -22,6 +22,9 @@ */ package com.iluwatar.reader.writer.lock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.locks.Lock; /** @@ -29,6 +32,8 @@ import java.util.concurrent.locks.Lock; */ public class Reader implements Runnable { + private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class); + private Lock readLock; private String name; @@ -55,8 +60,8 @@ public class Reader implements Runnable { * */ public void read() throws InterruptedException { - System.out.println(name + " begin"); + LOGGER.info("{} begin", name); Thread.sleep(250); - System.out.println(name + " finish"); + LOGGER.info("{} finish", name); } } 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 index fc3c3bb88..ce946f74f 100644 --- 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 @@ -22,6 +22,9 @@ */ package com.iluwatar.reader.writer.lock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.concurrent.locks.Lock; /** @@ -29,6 +32,8 @@ import java.util.concurrent.locks.Lock; */ public class Writer implements Runnable { + private static final Logger LOGGER = LoggerFactory.getLogger(Writer.class); + private Lock writeLock; private String name; @@ -55,8 +60,8 @@ public class Writer implements Runnable { * Simulate the write operation */ public void write() throws InterruptedException { - System.out.println(name + " begin"); + LOGGER.info("{} begin", name); Thread.sleep(250); - System.out.println(name + " finish"); + LOGGER.info("{} finish", name); } } 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 index a2496a3c0..dc8feb04f 100644 --- 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 @@ -31,13 +31,15 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; import org.mockito.InOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author hongshuwei@gmail.com */ public class ReaderAndWriterTest extends StdOutTest { - + private static final Logger LOGGER = LoggerFactory.getLogger(ReaderAndWriterTest.class); /** * Verify reader and writer can only get the lock to read and write orderly @@ -60,7 +62,7 @@ public class ReaderAndWriterTest extends StdOutTest { try { executeService.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.out.println("Error waiting for ExecutorService shutdown"); + LOGGER.error("Error waiting for ExecutorService shutdown", e); } final InOrder inOrder = inOrder(getStdOutMock()); @@ -91,7 +93,7 @@ public class ReaderAndWriterTest extends StdOutTest { try { executeService.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.out.println("Error waiting for ExecutorService shutdown"); + LOGGER.error("Error waiting for ExecutorService shutdown", e); } final InOrder inOrder = inOrder(getStdOutMock()); 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 index 7d51e977c..a51120bf8 100644 --- 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 @@ -31,12 +31,16 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; import org.mockito.InOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author hongshuwei@gmail.com */ public class ReaderTest extends StdOutTest { + private static final Logger LOGGER = LoggerFactory.getLogger(ReaderTest.class); + /** * Verify that multiple readers can get the read lock concurrently */ @@ -57,7 +61,7 @@ public class ReaderTest extends StdOutTest { try { executeService.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.out.println("Error waiting for ExecutorService shutdown"); + LOGGER.error("Error waiting for ExecutorService shutdown", e); } // Read operation will hold the read lock 250 milliseconds, so here we prove that multiple reads 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 index 765c491ff..729b5eff3 100644 --- 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 @@ -31,12 +31,16 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; import org.mockito.InOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author hongshuwei@gmail.com */ public class WriterTest extends StdOutTest { + private static final Logger LOGGER = LoggerFactory.getLogger(WriterTest.class); + /** * Verify that multiple writers will get the lock in order. */ @@ -58,7 +62,7 @@ public class WriterTest extends StdOutTest { try { executeService.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { - System.out.println("Error waiting for ExecutorService shutdown"); + 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 diff --git a/repository/src/main/java/com/iluwatar/repository/App.java b/repository/src/main/java/com/iluwatar/repository/App.java index 2807ae7ca..ab61852d2 100644 --- a/repository/src/main/java/com/iluwatar/repository/App.java +++ b/repository/src/main/java/com/iluwatar/repository/App.java @@ -24,6 +24,8 @@ package com.iluwatar.repository; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; /** @@ -43,6 +45,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -67,12 +71,12 @@ public class App { repository.save(terry); // Count Person records - System.out.println("Count Person records: " + repository.count()); + LOGGER.info("Count Person records: {}", repository.count()); // Print all records List persons = (List) repository.findAll(); for (Person person : persons) { - System.out.println(person); + LOGGER.info(person.toString()); } // Update Person @@ -80,24 +84,24 @@ public class App { nasta.setSurname("Spotakova"); repository.save(nasta); - System.out.println("Find by id 2: " + repository.findOne(2L)); + LOGGER.info("Find by id 2: {}", repository.findOne(2L)); // Remove record from Person repository.delete(2L); // count records - System.out.println("Count Person records: " + repository.count()); + LOGGER.info("Count Person records: {}", repository.count()); // find by name Person p = repository.findOne(new PersonSpecifications.NameEqualSpec("John")); - System.out.println("Find by John is " + p); + LOGGER.info("Find by John is {}", p); // find by age persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40)); - System.out.println("Find Person with age between 20,40: "); + LOGGER.info("Find Person with age between 20,40: "); for (Person person : persons) { - System.out.println(person); + LOGGER.info(person.toString()); } repository.deleteAll(); diff --git a/repository/src/main/java/com/iluwatar/repository/AppConfig.java b/repository/src/main/java/com/iluwatar/repository/AppConfig.java index 3e7093358..09f6753bb 100644 --- a/repository/src/main/java/com/iluwatar/repository/AppConfig.java +++ b/repository/src/main/java/com/iluwatar/repository/AppConfig.java @@ -30,6 +30,8 @@ import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.hibernate.jpa.HibernatePersistenceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @@ -44,6 +46,8 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @EnableJpaRepositories public class AppConfig { + private static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class); + /** * Creation of H2 db * @@ -117,12 +121,12 @@ public class AppConfig { repository.save(terry); // Count Person records - System.out.println("Count Person records: " + repository.count()); + LOGGER.info("Count Person records: {}", repository.count()); // Print all records List persons = (List) repository.findAll(); for (Person person : persons) { - System.out.println(person); + LOGGER.info(person.toString()); } // Update Person @@ -130,24 +134,24 @@ public class AppConfig { nasta.setSurname("Spotakova"); repository.save(nasta); - System.out.println("Find by id 2: " + repository.findOne(2L)); + LOGGER.info("Find by id 2: {}", repository.findOne(2L)); // Remove record from Person repository.delete(2L); // count records - System.out.println("Count Person records: " + repository.count()); + LOGGER.info("Count Person records: {}", repository.count()); // find by name Person p = repository.findOne(new PersonSpecifications.NameEqualSpec("John")); - System.out.println("Find by John is " + p); + LOGGER.info("Find by John is {}", p); // find by age persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40)); - System.out.println("Find Person with age between 20,40: "); + LOGGER.info("Find Person with age between 20,40: "); for (Person person : persons) { - System.out.println(person); + LOGGER.info(person.toString()); } context.close(); diff --git a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java index 413fb0eab..bb722a36d 100644 --- a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java +++ b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.resource.acquisition.is.initialization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Resource Acquisition Is Initialization pattern was developed for exception safe resource @@ -44,17 +47,19 @@ package com.iluwatar.resource.acquisition.is.initialization; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ public static void main(String[] args) throws Exception { try (SlidingDoor slidingDoor = new SlidingDoor()) { - System.out.println("Walking in."); + LOGGER.info("Walking in."); } try (TreasureChest treasureChest = new TreasureChest()) { - System.out.println("Looting contents."); + LOGGER.info("Looting contents."); } } } diff --git a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java index 3a1a35f2d..ac8512d15 100644 --- a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java +++ b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java @@ -22,6 +22,9 @@ */ package com.iluwatar.resource.acquisition.is.initialization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * SlidingDoor resource @@ -29,12 +32,14 @@ package com.iluwatar.resource.acquisition.is.initialization; */ public class SlidingDoor implements AutoCloseable { + private static final Logger LOGGER = LoggerFactory.getLogger(SlidingDoor.class); + public SlidingDoor() { - System.out.println("Sliding door opens."); + LOGGER.info("Sliding door opens."); } @Override public void close() throws Exception { - System.out.println("Sliding door closes."); + LOGGER.info("Sliding door closes."); } } diff --git a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java index e7b7ebab6..f020b5fa3 100644 --- a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java +++ b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java @@ -22,6 +22,9 @@ */ package com.iluwatar.resource.acquisition.is.initialization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.Closeable; import java.io.IOException; @@ -32,12 +35,14 @@ import java.io.IOException; */ public class TreasureChest implements Closeable { + private static final Logger LOGGER = LoggerFactory.getLogger(TreasureChest.class); + public TreasureChest() { - System.out.println("Treasure chest opens."); + LOGGER.info("Treasure chest opens."); } @Override public void close() throws IOException { - System.out.println("Treasure chest closes."); + LOGGER.info("Treasure chest closes."); } } diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/Customer.java b/semaphore/src/main/java/com/iluwatar/semaphore/Customer.java index 0a4713438..e0546edbe 100644 --- a/semaphore/src/main/java/com/iluwatar/semaphore/Customer.java +++ b/semaphore/src/main/java/com/iluwatar/semaphore/Customer.java @@ -22,12 +22,17 @@ */ package com.iluwatar.semaphore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A Customer attempts to repeatedly take Fruit from the FruitShop by * taking Fruit from FruitBowl instances. */ public class Customer extends Thread { + private static final Logger LOGGER = LoggerFactory.getLogger(Customer.class); + /** * Name of the Customer. */ @@ -63,13 +68,13 @@ public class Customer extends Thread { Fruit fruit; if (bowl != null && (fruit = bowl.take()) != null) { - System.out.println(name + " took an " + fruit); + LOGGER.info("{} took an {}", name, fruit); fruitBowl.put(fruit); fruitShop.returnBowl(bowl); } } - - System.out.println(name + " took " + fruitBowl); + + LOGGER.info("{} took {}", name, fruitBowl); } diff --git a/servant/src/main/java/com/iluwatar/servant/App.java b/servant/src/main/java/com/iluwatar/servant/App.java index 92829441d..aeb379846 100644 --- a/servant/src/main/java/com/iluwatar/servant/App.java +++ b/servant/src/main/java/com/iluwatar/servant/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.servant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; @@ -35,6 +38,8 @@ import java.util.ArrayList; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + static Servant jenkins = new Servant("Jenkins"); static Servant travis = new Servant("Travis"); @@ -73,9 +78,9 @@ public class App { // check your luck if (servant.checkIfYouWillBeHanged(guests)) { - System.out.println(servant.name + " will live another day"); + LOGGER.info("{} will live another day", servant.name); } else { - System.out.println("Poor " + servant.name + ". His days are numbered"); + LOGGER.info("Poor {}. His days are numbered", servant.name); } } } diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java index 8282d800c..bf15c5885 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java @@ -35,6 +35,8 @@ import com.iluwatar.servicelayer.spellbook.SpellbookDaoImpl; import com.iluwatar.servicelayer.wizard.Wizard; import com.iluwatar.servicelayer.wizard.WizardDao; import com.iluwatar.servicelayer.wizard.WizardDaoImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** @@ -57,6 +59,8 @@ import com.iluwatar.servicelayer.wizard.WizardDaoImpl; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -180,27 +184,27 @@ public class App { public static void queryData() { MagicService service = new MagicServiceImpl(new WizardDaoImpl(), new SpellbookDaoImpl(), new SpellDaoImpl()); - System.out.println("Enumerating all wizards"); + LOGGER.info("Enumerating all wizards"); for (Wizard w : service.findAllWizards()) { - System.out.println(w.getName()); + LOGGER.info(w.getName()); } - System.out.println("Enumerating all spellbooks"); + LOGGER.info("Enumerating all spellbooks"); for (Spellbook s : service.findAllSpellbooks()) { - System.out.println(s.getName()); + LOGGER.info(s.getName()); } - System.out.println("Enumerating all spells"); + LOGGER.info("Enumerating all spells"); for (Spell s : service.findAllSpells()) { - System.out.println(s.getName()); + LOGGER.info(s.getName()); } - System.out.println("Find wizards with spellbook 'Book of Idores'"); + LOGGER.info("Find wizards with spellbook 'Book of Idores'"); List wizardsWithSpellbook = service.findWizardsWithSpellbook("Book of Idores"); for (Wizard w : wizardsWithSpellbook) { - System.out.println(String.format("%s has 'Book of Idores'", w.getName())); + LOGGER.info("{} has 'Book of Idores'", w.getName()); } - System.out.println("Find wizards with spell 'Fireball'"); + LOGGER.info("Find wizards with spell 'Fireball'"); List wizardsWithSpell = service.findWizardsWithSpell("Fireball"); for (Wizard w : wizardsWithSpell) { - System.out.println(String.format("%s has 'Fireball'", w.getName())); + LOGGER.info("{} has 'Fireball'", w.getName()); } } } diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java b/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java index b30b97b65..eead0e197 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java @@ -28,12 +28,16 @@ import com.iluwatar.servicelayer.wizard.Wizard; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Produces the Hibernate {@link SessionFactory}. */ public final class HibernateUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(HibernateUtil.class); + /** * The cached session factory */ @@ -59,7 +63,7 @@ public final class HibernateUtil { .setProperty("hibernate.show_sql", "true") .setProperty("hibernate.hbm2ddl.auto", "create-drop").buildSessionFactory(); } catch (Throwable ex) { - System.err.println("Initial SessionFactory creation failed." + ex); + LOGGER.error("Initial SessionFactory creation failed.", ex); throw new ExceptionInInitializerError(ex); } } diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/InitContext.java b/service-locator/src/main/java/com/iluwatar/servicelocator/InitContext.java index 8063fc818..134eb6d89 100644 --- a/service-locator/src/main/java/com/iluwatar/servicelocator/InitContext.java +++ b/service-locator/src/main/java/com/iluwatar/servicelocator/InitContext.java @@ -22,6 +22,9 @@ */ package com.iluwatar.servicelocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * For JNDI lookup of services from the web.xml. Will match name of the service name that is being * requested and return a newly created service object with the name @@ -30,6 +33,8 @@ package com.iluwatar.servicelocator; */ public class InitContext { + private static final Logger LOGGER = LoggerFactory.getLogger(InitContext.class); + /** * Perform the lookup based on the service name. The returned object will need to be casted into a * {@link Service} @@ -39,10 +44,10 @@ public class InitContext { */ public Object lookup(String serviceName) { if (serviceName.equals("jndi/serviceA")) { - System.out.println("Looking up service A and creating new service for A"); + LOGGER.info("Looking up service A and creating new service for A"); return new ServiceImpl("jndi/serviceA"); } else if (serviceName.equals("jndi/serviceB")) { - System.out.println("Looking up service B and creating new service for B"); + LOGGER.info("Looking up service B and creating new service for B"); return new ServiceImpl("jndi/serviceB"); } else { return null; diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceCache.java b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceCache.java index 7e2169fcb..89b2a6638 100644 --- a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceCache.java +++ b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceCache.java @@ -22,6 +22,9 @@ */ package com.iluwatar.servicelocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.HashMap; import java.util.Map; @@ -35,6 +38,8 @@ import java.util.Map; */ public class ServiceCache { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCache.class); + private final Map serviceCache; public ServiceCache() { @@ -52,8 +57,8 @@ public class ServiceCache { for (String serviceJndiName : serviceCache.keySet()) { if (serviceJndiName.equals(serviceName)) { cachedService = serviceCache.get(serviceJndiName); - System.out.println("(cache call) Fetched service " + cachedService.getName() + "(" - + cachedService.getId() + ") from cache... !"); + LOGGER.info("(cache call) Fetched service {}({}) from cache... !", + cachedService.getName(), cachedService.getId()); } } return cachedService; diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java index 543fb8480..328926ce2 100644 --- a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java +++ b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java @@ -22,6 +22,9 @@ */ package com.iluwatar.servicelocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * This is a single service implementation of a sample service. This is the actual service that will * process the request. The reference for this service is to be looked upon in the JNDI server that @@ -31,6 +34,8 @@ package com.iluwatar.servicelocator; */ public class ServiceImpl implements Service { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceImpl.class); + private final String serviceName; private final int id; @@ -57,6 +62,6 @@ public class ServiceImpl implements Service { @Override public void execute() { - System.out.println("Service " + getName() + " is now executing with id " + getId()); + LOGGER.info("Service {} is now executing with id {}", getName(), getId()); } } diff --git a/singleton/src/main/java/com/iluwatar/singleton/App.java b/singleton/src/main/java/com/iluwatar/singleton/App.java index 4b505085a..31dcd1803 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/App.java +++ b/singleton/src/main/java/com/iluwatar/singleton/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.singleton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Singleton pattern ensures that the class can have only one existing instance per Java classloader * instance and provides global access to it. @@ -60,6 +63,8 @@ package com.iluwatar.singleton; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point. * @@ -70,35 +75,35 @@ public class App { // eagerly initialized singleton IvoryTower ivoryTower1 = IvoryTower.getInstance(); IvoryTower ivoryTower2 = IvoryTower.getInstance(); - System.out.println("ivoryTower1=" + ivoryTower1); - System.out.println("ivoryTower2=" + ivoryTower2); + LOGGER.info("ivoryTower1={}", ivoryTower1); + LOGGER.info("ivoryTower2={}", ivoryTower2); // lazily initialized singleton ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower1 = ThreadSafeLazyLoadedIvoryTower.getInstance(); ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower2 = ThreadSafeLazyLoadedIvoryTower.getInstance(); - System.out.println("threadSafeIvoryTower1=" + threadSafeIvoryTower1); - System.out.println("threadSafeIvoryTower2=" + threadSafeIvoryTower2); + LOGGER.info("threadSafeIvoryTower1={}", threadSafeIvoryTower1); + LOGGER.info("threadSafeIvoryTower2={}", threadSafeIvoryTower2); // enum singleton EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE; EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE; - System.out.println("enumIvoryTower1=" + enumIvoryTower1); - System.out.println("enumIvoryTower2=" + enumIvoryTower2); + LOGGER.info("enumIvoryTower1={}", enumIvoryTower1); + LOGGER.info("enumIvoryTower2={}", enumIvoryTower2); // double checked locking ThreadSafeDoubleCheckLocking dcl1 = ThreadSafeDoubleCheckLocking.getInstance(); - System.out.println(dcl1); + LOGGER.info(dcl1.toString()); ThreadSafeDoubleCheckLocking dcl2 = ThreadSafeDoubleCheckLocking.getInstance(); - System.out.println(dcl2); + LOGGER.info(dcl2.toString()); // initialize on demand holder idiom InitializingOnDemandHolderIdiom demandHolderIdiom = InitializingOnDemandHolderIdiom.getInstance(); - System.out.println(demandHolderIdiom); + LOGGER.info(demandHolderIdiom.toString()); InitializingOnDemandHolderIdiom demandHolderIdiom2 = InitializingOnDemandHolderIdiom.getInstance(); - System.out.println(demandHolderIdiom2); + LOGGER.info(demandHolderIdiom2.toString()); } } diff --git a/specification/src/main/java/com/iluwatar/specification/app/App.java b/specification/src/main/java/com/iluwatar/specification/app/App.java index 7cbd38470..7e85d2713 100644 --- a/specification/src/main/java/com/iluwatar/specification/app/App.java +++ b/specification/src/main/java/com/iluwatar/specification/app/App.java @@ -37,6 +37,8 @@ import com.iluwatar.specification.property.Color; import com.iluwatar.specification.property.Movement; import com.iluwatar.specification.selector.ColorSelector; import com.iluwatar.specification.selector.MovementSelector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -52,6 +54,8 @@ import com.iluwatar.specification.selector.MovementSelector; * */ public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** * Program entry point @@ -62,22 +66,22 @@ public class App { Arrays.asList(new Goblin(), new Octopus(), new Dragon(), new Shark(), new Troll(), new KillerBee()); // find all walking creatures - System.out.println("Find all walking creatures"); + LOGGER.info("Find all walking creatures"); List walkingCreatures = creatures.stream().filter(new MovementSelector(Movement.WALKING)) .collect(Collectors.toList()); - walkingCreatures.stream().forEach(System.out::println); + walkingCreatures.stream().forEach(c -> LOGGER.info(c.toString())); // find all dark creatures - System.out.println("Find all dark creatures"); + LOGGER.info("Find all dark creatures"); List darkCreatures = creatures.stream().filter(new ColorSelector(Color.DARK)).collect(Collectors.toList()); - darkCreatures.stream().forEach(System.out::println); + darkCreatures.stream().forEach(c -> LOGGER.info(c.toString())); // find all red and flying creatures - System.out.println("Find all red and flying creatures"); + LOGGER.info("Find all red and flying creatures"); List redAndFlyingCreatures = creatures.stream() .filter(new ColorSelector(Color.RED).and(new MovementSelector(Movement.FLYING))) .collect(Collectors.toList()); - redAndFlyingCreatures.stream().forEach(System.out::println); + redAndFlyingCreatures.stream().forEach(c -> LOGGER.info(c.toString())); } } diff --git a/state/src/main/java/com/iluwatar/state/AngryState.java b/state/src/main/java/com/iluwatar/state/AngryState.java index c58f85ae1..3ebbed142 100644 --- a/state/src/main/java/com/iluwatar/state/AngryState.java +++ b/state/src/main/java/com/iluwatar/state/AngryState.java @@ -22,6 +22,9 @@ */ package com.iluwatar.state; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Angry state. @@ -29,6 +32,8 @@ package com.iluwatar.state; */ public class AngryState implements State { + private static final Logger LOGGER = LoggerFactory.getLogger(AngryState.class); + private Mammoth mammoth; public AngryState(Mammoth mammoth) { @@ -37,12 +42,12 @@ public class AngryState implements State { @Override public void observe() { - System.out.println(String.format("%s is furious!", mammoth)); + LOGGER.info("{} is furious!", mammoth); } @Override public void onEnterState() { - System.out.println(String.format("%s gets angry!", mammoth)); + LOGGER.info("{} gets angry!", mammoth); } } diff --git a/state/src/main/java/com/iluwatar/state/PeacefulState.java b/state/src/main/java/com/iluwatar/state/PeacefulState.java index 23f4e893c..870298632 100644 --- a/state/src/main/java/com/iluwatar/state/PeacefulState.java +++ b/state/src/main/java/com/iluwatar/state/PeacefulState.java @@ -22,6 +22,9 @@ */ package com.iluwatar.state; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Peaceful state. @@ -29,6 +32,8 @@ package com.iluwatar.state; */ public class PeacefulState implements State { + private static final Logger LOGGER = LoggerFactory.getLogger(PeacefulState.class); + private Mammoth mammoth; public PeacefulState(Mammoth mammoth) { @@ -37,12 +42,12 @@ public class PeacefulState implements State { @Override public void observe() { - System.out.println(String.format("%s is calm and peaceful.", mammoth)); + LOGGER.info("{} is calm and peaceful.", mammoth); } @Override public void onEnterState() { - System.out.println(String.format("%s calms down.", mammoth)); + LOGGER.info("{} calms down.", mammoth); } } diff --git a/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java b/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java index aeb759ba8..fe5c5a8cd 100644 --- a/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java +++ b/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.stepbuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Step Builder Pattern * @@ -56,6 +59,8 @@ package com.iluwatar.stepbuilder; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -67,18 +72,18 @@ public class App { CharacterStepBuilder.newBuilder().name("Amberjill").fighterClass("Paladin") .withWeapon("Sword").noAbilities().build(); - System.out.println(warrior); + LOGGER.info(warrior.toString()); Character mage = CharacterStepBuilder.newBuilder().name("Riobard").wizardClass("Sorcerer") .withSpell("Fireball").withAbility("Fire Aura").withAbility("Teleport") .noMoreAbilities().build(); - System.out.println(mage); + LOGGER.info(mage.toString()); Character thief = CharacterStepBuilder.newBuilder().name("Desmond").fighterClass("Rogue").noWeapon().build(); - System.out.println(thief); + LOGGER.info(thief.toString()); } } diff --git a/strategy/src/main/java/com/iluwatar/strategy/App.java b/strategy/src/main/java/com/iluwatar/strategy/App.java index be8826fe3..28485701c 100644 --- a/strategy/src/main/java/com/iluwatar/strategy/App.java +++ b/strategy/src/main/java/com/iluwatar/strategy/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.strategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * The Strategy pattern (also known as the policy pattern) is a software design pattern that enables @@ -37,6 +40,8 @@ package com.iluwatar.strategy; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -44,27 +49,27 @@ public class App { */ public static void main(String[] args) { // GoF Strategy pattern - System.out.println("Green dragon spotted ahead!"); + LOGGER.info("Green dragon spotted ahead!"); DragonSlayer dragonSlayer = new DragonSlayer(new MeleeStrategy()); dragonSlayer.goToBattle(); - System.out.println("Red dragon emerges."); + LOGGER.info("Red dragon emerges."); dragonSlayer.changeStrategy(new ProjectileStrategy()); dragonSlayer.goToBattle(); - System.out.println("Black dragon lands before you."); + LOGGER.info("Black dragon lands before you."); dragonSlayer.changeStrategy(new SpellStrategy()); dragonSlayer.goToBattle(); // Java 8 Strategy pattern - System.out.println("Green dragon spotted ahead!"); + LOGGER.info("Green dragon spotted ahead!"); dragonSlayer = new DragonSlayer( - () -> System.out.println("With your Excalibur you severe the dragon's head!")); + () -> LOGGER.info("With your Excalibur you severe the dragon's head!")); dragonSlayer.goToBattle(); - System.out.println("Red dragon emerges."); - dragonSlayer.changeStrategy(() -> System.out.println( + LOGGER.info("Red dragon emerges."); + dragonSlayer.changeStrategy(() -> LOGGER.info( "You shoot the dragon with the magical crossbow and it falls dead on the ground!")); dragonSlayer.goToBattle(); - System.out.println("Black dragon lands before you."); - dragonSlayer.changeStrategy(() -> System.out.println( + LOGGER.info("Black dragon lands before you."); + dragonSlayer.changeStrategy(() -> LOGGER.info( "You cast the spell of disintegration and the dragon vaporizes in a pile of dust!")); dragonSlayer.goToBattle(); } diff --git a/strategy/src/main/java/com/iluwatar/strategy/MeleeStrategy.java b/strategy/src/main/java/com/iluwatar/strategy/MeleeStrategy.java index d17ff9041..d67f8b559 100644 --- a/strategy/src/main/java/com/iluwatar/strategy/MeleeStrategy.java +++ b/strategy/src/main/java/com/iluwatar/strategy/MeleeStrategy.java @@ -22,6 +22,9 @@ */ package com.iluwatar.strategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Melee strategy. @@ -29,8 +32,10 @@ package com.iluwatar.strategy; */ public class MeleeStrategy implements DragonSlayingStrategy { + private static final Logger LOGGER = LoggerFactory.getLogger(MeleeStrategy.class); + @Override public void execute() { - System.out.println("With your Excalibur you sever the dragon's head!"); + LOGGER.info("With your Excalibur you sever the dragon's head!"); } } diff --git a/strategy/src/main/java/com/iluwatar/strategy/ProjectileStrategy.java b/strategy/src/main/java/com/iluwatar/strategy/ProjectileStrategy.java index 7cd731167..ea88fdc8b 100644 --- a/strategy/src/main/java/com/iluwatar/strategy/ProjectileStrategy.java +++ b/strategy/src/main/java/com/iluwatar/strategy/ProjectileStrategy.java @@ -22,6 +22,9 @@ */ package com.iluwatar.strategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Projectile strategy. @@ -29,9 +32,10 @@ package com.iluwatar.strategy; */ public class ProjectileStrategy implements DragonSlayingStrategy { + private static final Logger LOGGER = LoggerFactory.getLogger(ProjectileStrategy.class); + @Override public void execute() { - System.out - .println("You shoot the dragon with the magical crossbow and it falls dead on the ground!"); + LOGGER.info("You shoot the dragon with the magical crossbow and it falls dead on the ground!"); } } diff --git a/strategy/src/main/java/com/iluwatar/strategy/SpellStrategy.java b/strategy/src/main/java/com/iluwatar/strategy/SpellStrategy.java index 6309ed31b..3264799bf 100644 --- a/strategy/src/main/java/com/iluwatar/strategy/SpellStrategy.java +++ b/strategy/src/main/java/com/iluwatar/strategy/SpellStrategy.java @@ -22,6 +22,9 @@ */ package com.iluwatar.strategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Spell strategy. @@ -29,10 +32,11 @@ package com.iluwatar.strategy; */ public class SpellStrategy implements DragonSlayingStrategy { + private static final Logger LOGGER = LoggerFactory.getLogger(SpellStrategy.class); + @Override public void execute() { - System.out - .println("You cast the spell of disintegration and the dragon vaporizes in a pile of dust!"); + LOGGER.info("You cast the spell of disintegration and the dragon vaporizes in a pile of dust!"); } } diff --git a/template-method/src/main/java/com/iluwatar/templatemethod/HitAndRunMethod.java b/template-method/src/main/java/com/iluwatar/templatemethod/HitAndRunMethod.java index 7a78576a1..49cbbd7dc 100644 --- a/template-method/src/main/java/com/iluwatar/templatemethod/HitAndRunMethod.java +++ b/template-method/src/main/java/com/iluwatar/templatemethod/HitAndRunMethod.java @@ -22,6 +22,9 @@ */ package com.iluwatar.templatemethod; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * HitAndRunMethod implementation of {@link StealingMethod}. @@ -29,6 +32,8 @@ package com.iluwatar.templatemethod; */ public class HitAndRunMethod extends StealingMethod { + private static final Logger LOGGER = LoggerFactory.getLogger(HitAndRunMethod.class); + @Override protected String pickTarget() { return "old goblin woman"; @@ -36,11 +41,11 @@ public class HitAndRunMethod extends StealingMethod { @Override protected void confuseTarget(String target) { - System.out.println("Approach the " + target + " from behind."); + LOGGER.info("Approach the {} from behind.", target); } @Override protected void stealTheItem(String target) { - System.out.println("Grab the handbag and run away fast!"); + LOGGER.info("Grab the handbag and run away fast!"); } } diff --git a/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java b/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java index c8c584cdd..85896d922 100644 --- a/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java +++ b/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java @@ -22,6 +22,9 @@ */ package com.iluwatar.templatemethod; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * StealingMethod defines skeleton for the algorithm. @@ -29,6 +32,8 @@ package com.iluwatar.templatemethod; */ public abstract class StealingMethod { + private static final Logger LOGGER = LoggerFactory.getLogger(StealingMethod.class); + protected abstract String pickTarget(); protected abstract void confuseTarget(String target); @@ -40,7 +45,7 @@ public abstract class StealingMethod { */ public void steal() { String target = pickTarget(); - System.out.println("The target has been chosen as " + target + "."); + LOGGER.info("The target has been chosen as {}.", target); confuseTarget(target); stealTheItem(target); } diff --git a/template-method/src/main/java/com/iluwatar/templatemethod/SubtleMethod.java b/template-method/src/main/java/com/iluwatar/templatemethod/SubtleMethod.java index 4fdb5d758..c7855fe4e 100644 --- a/template-method/src/main/java/com/iluwatar/templatemethod/SubtleMethod.java +++ b/template-method/src/main/java/com/iluwatar/templatemethod/SubtleMethod.java @@ -22,6 +22,9 @@ */ package com.iluwatar.templatemethod; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * SubtleMethod implementation of {@link StealingMethod}. @@ -29,6 +32,8 @@ package com.iluwatar.templatemethod; */ public class SubtleMethod extends StealingMethod { + private static final Logger LOGGER = LoggerFactory.getLogger(SubtleMethod.class); + @Override protected String pickTarget() { return "shop keeper"; @@ -36,11 +41,11 @@ public class SubtleMethod extends StealingMethod { @Override protected void confuseTarget(String target) { - System.out.println("Approach the " + target + " with tears running and hug him!"); + LOGGER.info("Approach the {} with tears running and hug him!", target); } @Override protected void stealTheItem(String target) { - System.out.println("While in close contact grab the " + target + "'s wallet."); + LOGGER.info("While in close contact grab the {}'s wallet.", target); } } diff --git a/thread-pool/src/main/java/com/iluwatar/threadpool/App.java b/thread-pool/src/main/java/com/iluwatar/threadpool/App.java index 16fbca35a..20d773c82 100644 --- a/thread-pool/src/main/java/com/iluwatar/threadpool/App.java +++ b/thread-pool/src/main/java/com/iluwatar/threadpool/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.threadpool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -43,6 +46,8 @@ import java.util.concurrent.Executors; * */ public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** * Program entry point @@ -51,7 +56,7 @@ public class App { */ public static void main(String[] args) { - System.out.println("Program started"); + LOGGER.info("Program started"); // Create a list of tasks to be executed List tasks = new ArrayList<>(); @@ -89,6 +94,6 @@ public class App { while (!executor.isTerminated()) { Thread.yield(); } - System.out.println("Program finished"); + LOGGER.info("Program finished"); } } diff --git a/thread-pool/src/main/java/com/iluwatar/threadpool/Worker.java b/thread-pool/src/main/java/com/iluwatar/threadpool/Worker.java index 1354cab41..1740b289e 100644 --- a/thread-pool/src/main/java/com/iluwatar/threadpool/Worker.java +++ b/thread-pool/src/main/java/com/iluwatar/threadpool/Worker.java @@ -22,6 +22,9 @@ */ package com.iluwatar.threadpool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * Worker implements {@link Runnable} and thus can be executed by {@link ExecutorService} @@ -29,6 +32,8 @@ package com.iluwatar.threadpool; */ public class Worker implements Runnable { + private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class); + private final Task task; public Worker(final Task task) { @@ -37,8 +42,7 @@ public class Worker implements Runnable { @Override public void run() { - System.out.println(String.format("%s processing %s", Thread.currentThread().getName(), - task.toString())); + LOGGER.info("{} processing {}", Thread.currentThread().getName(), task.toString()); try { Thread.sleep(task.getTimeMs()); } catch (InterruptedException e) { diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java index 066b6e737..14ebcab40 100644 --- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java +++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.tolerantreader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; /** @@ -41,31 +44,33 @@ import java.io.IOException; */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point */ public static void main(String[] args) throws IOException, ClassNotFoundException { // Write V1 RainbowFish fishV1 = new RainbowFish("Zed", 10, 11, 12); - System.out.println(String.format("fishV1 name=%s age=%d length=%d weight=%d", fishV1.getName(), - fishV1.getAge(), fishV1.getLengthMeters(), fishV1.getWeightTons())); + LOGGER.info("fishV1 name={} age={} length={} weight={}", fishV1.getName(), + fishV1.getAge(), fishV1.getLengthMeters(), fishV1.getWeightTons()); RainbowFishSerializer.writeV1(fishV1, "fish1.out"); // Read V1 RainbowFish deserializedFishV1 = RainbowFishSerializer.readV1("fish1.out"); - System.out.println(String.format("deserializedFishV1 name=%s age=%d length=%d weight=%d", + LOGGER.info("deserializedFishV1 name={} age={} length={} weight={}", deserializedFishV1.getName(), deserializedFishV1.getAge(), - deserializedFishV1.getLengthMeters(), deserializedFishV1.getWeightTons())); + deserializedFishV1.getLengthMeters(), deserializedFishV1.getWeightTons()); // Write V2 RainbowFishV2 fishV2 = new RainbowFishV2("Scar", 5, 12, 15, true, true, true); - System.out.println(String.format( - "fishV2 name=%s age=%d length=%d weight=%d sleeping=%b hungry=%b angry=%b", + LOGGER.info( + "fishV2 name={} age={} length={} weight={} sleeping={} hungry={} angry={}", fishV2.getName(), fishV2.getAge(), fishV2.getLengthMeters(), fishV2.getWeightTons(), - fishV2.getHungry(), fishV2.getAngry(), fishV2.getSleeping())); + fishV2.getHungry(), fishV2.getAngry(), fishV2.getSleeping()); RainbowFishSerializer.writeV2(fishV2, "fish2.out"); // Read V2 with V1 method RainbowFish deserializedFishV2 = RainbowFishSerializer.readV1("fish2.out"); - System.out.println(String.format("deserializedFishV2 name=%s age=%d length=%d weight=%d", + LOGGER.info("deserializedFishV2 name={} age={} length={} weight={}", deserializedFishV2.getName(), deserializedFishV2.getAge(), - deserializedFishV2.getLengthMeters(), deserializedFishV2.getWeightTons())); + deserializedFishV2.getLengthMeters(), deserializedFishV2.getWeightTons()); } } diff --git a/twin/src/main/java/com/iluwatar/twin/BallItem.java b/twin/src/main/java/com/iluwatar/twin/BallItem.java index 0188b5731..0c47bc91c 100644 --- a/twin/src/main/java/com/iluwatar/twin/BallItem.java +++ b/twin/src/main/java/com/iluwatar/twin/BallItem.java @@ -23,6 +23,9 @@ package com.iluwatar.twin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * This class represents a Ball which extends {@link GameItem} and implements the logic for ball * item, like move and draw. It hold a reference of {@link BallThread} to delegate the suspend and @@ -30,6 +33,8 @@ package com.iluwatar.twin; */ public class BallItem extends GameItem { + private static final Logger LOGGER = LoggerFactory.getLogger(BallItem.class); + private boolean isSuspended; private BallThread twin; @@ -41,11 +46,11 @@ public class BallItem extends GameItem { @Override public void doDraw() { - System.out.println("doDraw"); + LOGGER.info("doDraw"); } public void move() { - System.out.println("move"); + LOGGER.info("move"); } @Override diff --git a/twin/src/main/java/com/iluwatar/twin/BallThread.java b/twin/src/main/java/com/iluwatar/twin/BallThread.java index 194d85b06..6dea979be 100644 --- a/twin/src/main/java/com/iluwatar/twin/BallThread.java +++ b/twin/src/main/java/com/iluwatar/twin/BallThread.java @@ -23,6 +23,9 @@ package com.iluwatar.twin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * This class is a UI thread for drawing the {@link BallItem}, and provide the method for suspend * and resume. It hold the reference of {@link BallItem} to delegate the draw task. @@ -31,6 +34,8 @@ package com.iluwatar.twin; public class BallThread extends Thread { + private static final Logger LOGGER = LoggerFactory.getLogger(BallThread.class); + private BallItem twin; private volatile boolean isSuspended; @@ -61,12 +66,12 @@ public class BallThread extends Thread { public void suspendMe() { isSuspended = true; - System.out.println("Begin to suspend BallThread"); + LOGGER.info("Begin to suspend BallThread"); } public void resumeMe() { isSuspended = false; - System.out.println("Begin to resume BallThread"); + LOGGER.info("Begin to resume BallThread"); } public void stopMe() { diff --git a/twin/src/main/java/com/iluwatar/twin/GameItem.java b/twin/src/main/java/com/iluwatar/twin/GameItem.java index 08d7dcce7..da2cef7a2 100644 --- a/twin/src/main/java/com/iluwatar/twin/GameItem.java +++ b/twin/src/main/java/com/iluwatar/twin/GameItem.java @@ -24,16 +24,21 @@ package com.iluwatar.twin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * GameItem is a common class which provides some common methods for game object. */ public abstract class GameItem { + private static final Logger LOGGER = LoggerFactory.getLogger(GameItem.class); + /** * Template method, do some common logic before draw */ public void draw() { - System.out.println("draw"); + LOGGER.info("draw"); doDraw(); } diff --git a/value-object/src/main/java/com/iluwatar/value/object/App.java b/value-object/src/main/java/com/iluwatar/value/object/App.java index 1e943d054..238258441 100644 --- a/value-object/src/main/java/com/iluwatar/value/object/App.java +++ b/value-object/src/main/java/com/iluwatar/value/object/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.value.object; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A Value Object are objects which follow value semantics rather than reference semantics. This * means value objects' equality are not based on identity. Two value objects are equal when they @@ -38,6 +41,9 @@ package com.iluwatar.value.object; * Colebourne's term VALJO : http://blog.joda.org/2014/03/valjos-value-java-objects.html */ public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * This practice creates three HeroStats(Value object) and checks equality between those. */ @@ -46,9 +52,9 @@ public class App { HeroStat statB = HeroStat.valueOf(10, 5, 0); HeroStat statC = HeroStat.valueOf(5, 1, 8); - System.out.println(statA.toString()); + LOGGER.info(statA.toString()); - System.out.println("Is statA and statB equal : " + statA.equals(statB)); - System.out.println("Is statA and statC equal : " + statA.equals(statC)); + LOGGER.info("Is statA and statB equal : {}", statA.equals(statB)); + LOGGER.info("Is statA and statC equal : {}", statA.equals(statC)); } } diff --git a/visitor/src/main/java/com/iluwatar/visitor/CommanderVisitor.java b/visitor/src/main/java/com/iluwatar/visitor/CommanderVisitor.java index 6e54c7861..466c12f51 100644 --- a/visitor/src/main/java/com/iluwatar/visitor/CommanderVisitor.java +++ b/visitor/src/main/java/com/iluwatar/visitor/CommanderVisitor.java @@ -22,6 +22,9 @@ */ package com.iluwatar.visitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * CommanderVisitor @@ -29,6 +32,8 @@ package com.iluwatar.visitor; */ public class CommanderVisitor implements UnitVisitor { + private static final Logger LOGGER = LoggerFactory.getLogger(CommanderVisitor.class); + @Override public void visitSoldier(Soldier soldier) { // Do nothing @@ -41,6 +46,6 @@ public class CommanderVisitor implements UnitVisitor { @Override public void visitCommander(Commander commander) { - System.out.println("Good to see you " + commander); + LOGGER.info("Good to see you {}", commander); } } diff --git a/visitor/src/main/java/com/iluwatar/visitor/SergeantVisitor.java b/visitor/src/main/java/com/iluwatar/visitor/SergeantVisitor.java index 4fca0a5bd..aa06cb2ad 100644 --- a/visitor/src/main/java/com/iluwatar/visitor/SergeantVisitor.java +++ b/visitor/src/main/java/com/iluwatar/visitor/SergeantVisitor.java @@ -22,6 +22,9 @@ */ package com.iluwatar.visitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * SergeantVisitor @@ -29,6 +32,8 @@ package com.iluwatar.visitor; */ public class SergeantVisitor implements UnitVisitor { + private static final Logger LOGGER = LoggerFactory.getLogger(SergeantVisitor.class); + @Override public void visitSoldier(Soldier soldier) { // Do nothing @@ -36,7 +41,7 @@ public class SergeantVisitor implements UnitVisitor { @Override public void visitSergeant(Sergeant sergeant) { - System.out.println("Hello " + sergeant); + LOGGER.info("Hello {}", sergeant); } @Override diff --git a/visitor/src/main/java/com/iluwatar/visitor/SoldierVisitor.java b/visitor/src/main/java/com/iluwatar/visitor/SoldierVisitor.java index fff24f699..0907a2531 100644 --- a/visitor/src/main/java/com/iluwatar/visitor/SoldierVisitor.java +++ b/visitor/src/main/java/com/iluwatar/visitor/SoldierVisitor.java @@ -22,6 +22,9 @@ */ package com.iluwatar.visitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * SoldierVisitor @@ -29,9 +32,11 @@ package com.iluwatar.visitor; */ public class SoldierVisitor implements UnitVisitor { + private static final Logger LOGGER = LoggerFactory.getLogger(SoldierVisitor.class); + @Override public void visitSoldier(Soldier soldier) { - System.out.println("Greetings " + soldier); + LOGGER.info("Greetings {}", soldier); } @Override From 56b088425814c975e9983a3aa3d99be2ada6d1e8 Mon Sep 17 00:00:00 2001 From: igeligel Date: Mon, 24 Oct 2016 15:28:27 +0200 Subject: [PATCH 093/492] Change name of variables in test #498 --- .../test/RoyaltyObjectMotherTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java index feba71a1b..ebe536d24 100644 --- a/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java +++ b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java @@ -45,26 +45,26 @@ public class RoyaltyObjectMotherTest { @Test public void queenIsBlockingFlirtCauseDrunkKing() { - King soberUnhappyKing = RoyaltyObjectMother.createDrunkKing(); + King drunkUnhappyKing = RoyaltyObjectMother.createDrunkKing(); Queen notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen(); - soberUnhappyKing.flirt(notFlirtyQueen); - assertFalse(soberUnhappyKing.isHappy()); + drunkUnhappyKing.flirt(notFlirtyQueen); + assertFalse(drunkUnhappyKing.isHappy()); } @Test public void queenIsBlockingFlirt() { - King soberUnhappyKing = RoyaltyObjectMother.createHappyKing(); + King soberHappyKing = RoyaltyObjectMother.createHappyKing(); Queen notFlirtyQueen = RoyaltyObjectMother.createNotFlirtyQueen(); - soberUnhappyKing.flirt(notFlirtyQueen); - assertFalse(soberUnhappyKing.isHappy()); + soberHappyKing.flirt(notFlirtyQueen); + assertFalse(soberHappyKing.isHappy()); } @Test public void successfullKingFlirt() { - King soberUnhappyKing = RoyaltyObjectMother.createHappyKing(); + King soberHappyKing = RoyaltyObjectMother.createHappyKing(); Queen flirtyQueen = RoyaltyObjectMother.createFlirtyQueen(); - soberUnhappyKing.flirt(flirtyQueen); - assertTrue(soberUnhappyKing.isHappy()); + soberHappyKing.flirt(flirtyQueen); + assertTrue(soberHappyKing.isHappy()); } @Test From 20295316c2f43e36ac3748551bf45ce60194c635 Mon Sep 17 00:00:00 2001 From: igeligel Date: Mon, 24 Oct 2016 15:30:17 +0200 Subject: [PATCH 094/492] add entry to parent pom.xml #498 --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 144b8efff..7aec509d4 100644 --- a/pom.xml +++ b/pom.xml @@ -132,6 +132,7 @@ aggregator-microservices promise page-object + object-mother From 74ac79b01ecb5fe47810e3cfba71e274349144a6 Mon Sep 17 00:00:00 2001 From: igeligel Date: Mon, 24 Oct 2016 15:33:25 +0200 Subject: [PATCH 095/492] Fix pom.xml --- pom.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 598386753..fc68a3830 100644 --- a/pom.xml +++ b/pom.xml @@ -132,13 +132,10 @@ aggregator-microservices promise page-object -<<<<<<< HEAD + event-asynchronous object-mother -======= - event-asynchronous ->>>>>>> refs/remotes/iluwatar/master From 6aed26e61e2af5d3574eaf6b842094ea041947da Mon Sep 17 00:00:00 2001 From: igeligel Date: Mon, 24 Oct 2016 15:43:52 +0200 Subject: [PATCH 096/492] Fix pom.xml Deleted tag because i added it one time more than neccessary --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index fc68a3830..76e108a57 100644 --- a/pom.xml +++ b/pom.xml @@ -135,7 +135,6 @@ event-asynchronous object-mother - From 2a77ac29e994cecc50f5ee5e461abdcb316dbaa3 Mon Sep 17 00:00:00 2001 From: Amit Dixit Date: Wed, 26 Oct 2016 16:59:36 +0530 Subject: [PATCH 097/492] FirstCut++ FirstCut++ --- module/README.md | 29 +++ module/pom.xml | 45 +++++ .../main/java/com/iluwatar/module/App.java | 73 +++++++ .../iluwatar/module/FilePrinterModule.java | 100 ++++++++++ module/src/main/resources/log4j.xml | 41 ++++ .../java/com/iluwatar/module/AppTest.java | 37 ++++ .../java/com/iluwatar/module/ModuleTest.java | 180 ++++++++++++++++++ pom.xml | 1 + 8 files changed, 506 insertions(+) create mode 100644 module/README.md create mode 100644 module/pom.xml create mode 100644 module/src/main/java/com/iluwatar/module/App.java create mode 100644 module/src/main/java/com/iluwatar/module/FilePrinterModule.java create mode 100644 module/src/main/resources/log4j.xml create mode 100644 module/src/test/java/com/iluwatar/module/AppTest.java create mode 100644 module/src/test/java/com/iluwatar/module/ModuleTest.java diff --git a/module/README.md b/module/README.md new file mode 100644 index 000000000..d3d6b8746 --- /dev/null +++ b/module/README.md @@ -0,0 +1,29 @@ +--- +layout: pattern +title: Module +folder: module +permalink: /patterns/module/ +pumlid: JShB3OGm303HLg20nFVjnYGM1CN6ycTfVtFSsnjfzY5jPgUqkLqHwXy0mxUU8wuyqidQ8q4IjJqCO-QBWGOtVh5qyd5AKOmW4mT6Nu2-ZiAekapH_hkcSTNa-GC0 +categories: Persistence Tier +tags: + - Java + - Difficulty-Beginner +--- + +## Intent +A layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself + +![alt text](./etc/module.png "Module") + +## Applicability +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. + +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. + +It supports specific cases where a class or object can be considered structured, procedural data. And, vice versa, migrate structured, procedural data, and considered as object-oriented. + +## Credits + +* [Module](https://en.wikipedia.org/wiki/Module_pattern) diff --git a/module/pom.xml b/module/pom.xml new file mode 100644 index 000000000..bc43e3e09 --- /dev/null +++ b/module/pom.xml @@ -0,0 +1,45 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.14.0-SNAPSHOT + + module + + + junit + junit + test + + + log4j + log4j + + + diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java new file mode 100644 index 000000000..9dab6a00c --- /dev/null +++ b/module/src/main/java/com/iluwatar/module/App.java @@ -0,0 +1,73 @@ +/** + * The MIT License Copyright (c) 2016 Amit Dixit + * + * 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 Data Mapper (DM) is a layer of software that separates the in-memory + * objects from the database. Its responsibility is to transfer data between the + * two and also to isolate them from each other. With Data Mapper the in-memory + * objects needn't know even that there's a database present; they need no SQL + * interface code, and certainly no knowledge of the database schema. (The + * database schema is always ignorant of the objects that use it.) Since it's a + * form of Mapper , Data Mapper itself is even unknown to the domain layer. + *

    + * The below example demonstrates basic CRUD operations: Create, Read, Update, + * and Delete. + * + */ +public final class App { + + private static final String OUTPUT_FILE = "output.txt"; + private static final String ERROR_FILE = "error.txt"; + + public static FilePrinterModule filePrinterModule = null; + + public static void prepare() throws FileNotFoundException { + filePrinterModule = FilePrinterModule.getSingleton(); + + filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + } + + public static void unprepare() { + filePrinterModule.unprepare(); + } + + public static final void execute(final String... args) { + filePrinterModule.printString("Hello World"); + } + + /** + * Program entry point. + * + * @param args + * command line args. + * @throws FileNotFoundException + */ + public static final void main(final String... args) + throws FileNotFoundException { + prepare(); + execute(args); + unprepare(); + } + + private App() { + } +} diff --git a/module/src/main/java/com/iluwatar/module/FilePrinterModule.java b/module/src/main/java/com/iluwatar/module/FilePrinterModule.java new file mode 100644 index 000000000..879492248 --- /dev/null +++ b/module/src/main/java/com/iluwatar/module/FilePrinterModule.java @@ -0,0 +1,100 @@ +package com.iluwatar.module; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; + +import org.apache.log4j.Logger; + +/** + * The MIT License Copyright (c) 2016 Amit Dixit + * + * 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. + */ +public final class FilePrinterModule { + + private static final Logger logger = Logger + .getLogger(FilePrinterModule.class); + + private static FilePrinterModule singleton = null; + + public PrintStream output = null; + public PrintStream error = null; + + private FilePrinterModule() { + } + + public static final FilePrinterModule getSingleton() { + + if (FilePrinterModule.singleton == null) { + FilePrinterModule.singleton = new FilePrinterModule(); + } + + return FilePrinterModule.singleton; + } + + /** + * + * @throws FileNotFoundException + */ + public final void prepare(final String outputFile, final String errorFile) + throws FileNotFoundException { + + logger.debug("MainModule::prepare();"); + + this.output = new PrintStream(new FileOutputStream(outputFile)); + this.error = new PrintStream(new FileOutputStream(errorFile)); + } + + /** + * + */ + public final void unprepare() { + + if (this.output != null) { + + this.output.flush(); + this.output.close(); + } + + if (this.error != null) { + + this.error.flush(); + this.error.close(); + } + + logger.debug("MainModule::unprepare();"); + } + + /** + * + * @param value + */ + public final void printString(final String value) { + this.output.print(value); + } + + /** + * + * @param value + */ + public final void printErrorString(final String value) { + this.error.print(value); + } +} diff --git a/module/src/main/resources/log4j.xml b/module/src/main/resources/log4j.xml new file mode 100644 index 000000000..b591c17e1 --- /dev/null +++ b/module/src/main/resources/log4j.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java new file mode 100644 index 000000000..46c12ef38 --- /dev/null +++ b/module/src/test/java/com/iluwatar/module/AppTest.java @@ -0,0 +1,37 @@ +/** + * The MIT License Copyright (c) 2016 Amit Dixit + * + * 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 com.iluwatar.module.App; + +import org.junit.Test; + +/** + * Tests that Data-Mapper example runs without errors. + */ +public final class AppTest { + + @Test + public void test() throws FileNotFoundException { + final String[] args = {}; + App.main(args); + } +} diff --git a/module/src/test/java/com/iluwatar/module/ModuleTest.java b/module/src/test/java/com/iluwatar/module/ModuleTest.java new file mode 100644 index 000000000..797e7f26a --- /dev/null +++ b/module/src/test/java/com/iluwatar/module/ModuleTest.java @@ -0,0 +1,180 @@ +/** + * The MIT License Copyright (c) 2016 Amit Dixit + * + * 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.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +import org.apache.log4j.Logger; +import org.junit.Test; + +/** + * The Data Mapper (DM) is a layer of software that separates the in-memory + * objects from the database. Its responsibility is to transfer data between the + * two and also to isolate them from each other. With Data Mapper the in-memory + * objects needn't know even that there's a database present; they need no SQL + * interface code, and certainly no knowledge of the database schema. (The + * database schema is always ignorant of the objects that use it.) Since it's a + * form of Mapper , Data Mapper itself is even unknown to the domain layer. + *

    + */ +public class ModuleTest { + + private static final Logger logger = Logger.getLogger(ModuleTest.class); + + 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 + */ + @Test + public void testPositiveMessage() throws IOException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FilePrinterModule filePrinterModule = FilePrinterModule + .getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + + /* Print 'Message' in file */ + filePrinterModule.printString(MESSAGE); + + /* Test if 'Message' is printed in file */ + assertEquals(readFirstLine(OUTPUT_FILE), MESSAGE); + + /* Unprepare to cleanup the modules */ + filePrinterModule.unprepare(); + } + + /** + * This test verify that nothing is printed in output file + * + * @throws IOException + */ + @Test + public void testNegativeMessage() throws IOException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FilePrinterModule filePrinterModule = FilePrinterModule + .getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + + /* Test if nothing is printed in file */ + assertEquals(readFirstLine(OUTPUT_FILE), null); + + /* Unprepare to cleanup the modules */ + filePrinterModule.unprepare(); + } + + /** + * This test verify that 'ERROR' is perfectly printed in error file + * + * @throws FileNotFoundException + */ + @Test + public void testPositiveErrorMessage() throws FileNotFoundException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FilePrinterModule filePrinterModule = FilePrinterModule + .getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + + /* Print 'Error' in file */ + filePrinterModule.printErrorString(ERROR); + + /* Test if 'Message' is printed in file */ + assertEquals(readFirstLine(ERROR_FILE), ERROR); + + /* Unprepare to cleanup the modules */ + filePrinterModule.unprepare(); + } + + /** + * This test verify that nothing is printed in error file + * + * @throws FileNotFoundException + */ + @Test + public void testNegativeErrorMessage() throws FileNotFoundException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FilePrinterModule filePrinterModule = FilePrinterModule + .getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + + /* Test if nothing is printed in file */ + assertEquals(readFirstLine(ERROR_FILE), null); + + /* Unprepare to cleanup the modules */ + filePrinterModule.unprepare(); + } + + /** + * Utility method to read first line of a file + * + * @param file + * @return + */ + private static final String readFirstLine(final String file) { + + String firstLine = null; + BufferedReader bufferedReader = null; + try { + + /* Create a buffered reader */ + bufferedReader = new BufferedReader(new FileReader(file)); + + /* Read the line */ + firstLine = bufferedReader.readLine(); + + logger.info("ModuleTest::readFile() : firstLine : " + firstLine); + + } catch (final IOException e) { + logger.error("ModuleTest::readFile()", e); + } finally { + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (final IOException e) { + logger.error("ModuleTest::readFile()", e); + } + } + } + + return firstLine; + } +} diff --git a/pom.xml b/pom.xml index 538058a81..a73992607 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,7 @@ factory-kit feature-toggle value-object + module monad mute-idiom mutex From 7015e95ac3b8560423b0a417683ab90ea5814599 Mon Sep 17 00:00:00 2001 From: Amit Dixit Date: Thu, 27 Oct 2016 15:55:08 +0530 Subject: [PATCH 098/492] SecondCut++ SecondCut++ --- module/README.md | 8 +- module/etc/module.png | Bin 0 -> 18027 bytes module/etc/module.ucls | 69 ++++++ .../main/java/com/iluwatar/module/App.java | 28 ++- .../iluwatar/module/ConsoleLoggerModule.java | 106 +++++++++ ...interModule.java => FileLoggerModule.java} | 61 +++--- .../java/com/iluwatar/module/ModuleTest.java | 203 +++++++++++++++--- 7 files changed, 403 insertions(+), 72 deletions(-) create mode 100644 module/etc/module.png create mode 100644 module/etc/module.ucls create mode 100644 module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java rename module/src/main/java/com/iluwatar/module/{FilePrinterModule.java => FileLoggerModule.java} (57%) diff --git a/module/README.md b/module/README.md index d3d6b8746..24bd3f543 100644 --- a/module/README.md +++ b/module/README.md @@ -4,26 +4,22 @@ title: Module folder: module permalink: /patterns/module/ pumlid: JShB3OGm303HLg20nFVjnYGM1CN6ycTfVtFSsnjfzY5jPgUqkLqHwXy0mxUU8wuyqidQ8q4IjJqCO-QBWGOtVh5qyd5AKOmW4mT6Nu2-ZiAekapH_hkcSTNa-GC0 -categories: Persistence Tier +categories: Creational Pattern tags: - Java - Difficulty-Beginner --- ## Intent -A layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself +Module pattern is used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept. ![alt text](./etc/module.png "Module") ## Applicability -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. - 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. -It supports specific cases where a class or object can be considered structured, procedural data. And, vice versa, migrate structured, procedural data, and considered as object-oriented. - ## Credits * [Module](https://en.wikipedia.org/wiki/Module_pattern) diff --git a/module/etc/module.png b/module/etc/module.png new file mode 100644 index 0000000000000000000000000000000000000000..a26807d290c0d2aced42c5e5d48cf0780e9c4d2b GIT binary patch literal 18027 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�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 b&*xx@wCm+^Q{eyCf+Z;`E0Qa$`}Y3>Bi8;O literal 0 HcmV?d00001 diff --git a/module/etc/module.ucls b/module/etc/module.ucls new file mode 100644 index 000000000..d2519b856 --- /dev/null +++ b/module/etc/module.ucls @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java index 9dab6a00c..0ca43d5c2 100644 --- a/module/src/main/java/com/iluwatar/module/App.java +++ b/module/src/main/java/com/iluwatar/module/App.java @@ -35,23 +35,35 @@ import java.io.FileNotFoundException; */ public final class App { - private static final String OUTPUT_FILE = "output.txt"; - private static final String ERROR_FILE = "error.txt"; - - public static FilePrinterModule filePrinterModule = null; + public static FileLoggerModule fileLoggerModule = null; + public static ConsoleLoggerModule consoleLoggerModule = null; public static void prepare() throws FileNotFoundException { - filePrinterModule = FilePrinterModule.getSingleton(); + + fileLoggerModule = FileLoggerModule.getSingleton(); + consoleLoggerModule = ConsoleLoggerModule.getSingleton(); - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + /* Prepare modules */ + fileLoggerModule.prepare(); + consoleLoggerModule.prepare(); } public static void unprepare() { - filePrinterModule.unprepare(); + + /* Close all resources */ + fileLoggerModule.unprepare(); + consoleLoggerModule.unprepare(); } public static final void execute(final String... args) { - filePrinterModule.printString("Hello World"); + + /* Send logs on file system */ + fileLoggerModule.printString("Message"); + fileLoggerModule.printErrorString("Error"); + + /* Send logs on console */ + consoleLoggerModule.printString("Message"); + consoleLoggerModule.printErrorString("Error"); } /** diff --git a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java new file mode 100644 index 000000000..097f85b0e --- /dev/null +++ b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java @@ -0,0 +1,106 @@ +/** + * The MIT License Copyright (c) 2016 Amit Dixit + * + * 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.PrintStream; + +import org.apache.log4j.Logger; + +/** + * 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 Console logger module, which can print + * simple and error messages in two designated formats + */ +public class ConsoleLoggerModule { + + private static final Logger logger = Logger + .getLogger(ConsoleLoggerModule.class); + + private static ConsoleLoggerModule singleton = null; + + public PrintStream output = null; + public PrintStream error = null; + + private ConsoleLoggerModule() { + } + + public static final ConsoleLoggerModule getSingleton() { + + if (ConsoleLoggerModule.singleton == null) { + ConsoleLoggerModule.singleton = new ConsoleLoggerModule(); + } + + return ConsoleLoggerModule.singleton; + } + + /** + * + * @throws FileNotFoundException + */ + public final void prepare() { + + logger.debug("ConsoleLoggerModule::prepare();"); + + this.output = new PrintStream(System.out); + this.error = new PrintStream(System.err); + } + + /** + * + */ + public final 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();"); + } + + /** + * + * @param value + */ + public final void printString(final String value) { + this.output.println(value); + } + + /** + * + * @param value + */ + public final void printErrorString(final String value) { + this.error.println(value); + } +} diff --git a/module/src/main/java/com/iluwatar/module/FilePrinterModule.java b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java similarity index 57% rename from module/src/main/java/com/iluwatar/module/FilePrinterModule.java rename to module/src/main/java/com/iluwatar/module/FileLoggerModule.java index 879492248..d1df062de 100644 --- a/module/src/main/java/com/iluwatar/module/FilePrinterModule.java +++ b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java @@ -1,11 +1,3 @@ -package com.iluwatar.module; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; - -import org.apache.log4j.Logger; - /** * The MIT License Copyright (c) 2016 Amit Dixit * @@ -27,39 +19,60 @@ import org.apache.log4j.Logger; * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -public final class FilePrinterModule { +package com.iluwatar.module; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; + +import org.apache.log4j.Logger; + +/** + * 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 File logger module, which can print simple + * and error messages in two designated files + */ +public final class FileLoggerModule { private static final Logger logger = Logger - .getLogger(FilePrinterModule.class); + .getLogger(FileLoggerModule.class); - private static FilePrinterModule singleton = null; + 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 FilePrinterModule() { + private FileLoggerModule() { } - public static final FilePrinterModule getSingleton() { + public static final FileLoggerModule getSingleton() { - if (FilePrinterModule.singleton == null) { - FilePrinterModule.singleton = new FilePrinterModule(); + if (FileLoggerModule.singleton == null) { + FileLoggerModule.singleton = new FileLoggerModule(); } - return FilePrinterModule.singleton; + return FileLoggerModule.singleton; } /** * * @throws FileNotFoundException */ - public final void prepare(final String outputFile, final String errorFile) - throws FileNotFoundException { + public final void prepare() throws FileNotFoundException { - logger.debug("MainModule::prepare();"); + logger.debug("FileLoggerModule::prepare();"); - this.output = new PrintStream(new FileOutputStream(outputFile)); - this.error = new PrintStream(new FileOutputStream(errorFile)); + this.output = new PrintStream(new FileOutputStream(OUTPUT_FILE)); + this.error = new PrintStream(new FileOutputStream(ERROR_FILE)); } /** @@ -79,7 +92,7 @@ public final class FilePrinterModule { this.error.close(); } - logger.debug("MainModule::unprepare();"); + logger.debug("FileLoggerModule::unprepare();"); } /** @@ -87,7 +100,7 @@ public final class FilePrinterModule { * @param value */ public final void printString(final String value) { - this.output.print(value); + this.output.println(value); } /** @@ -95,6 +108,6 @@ public final class FilePrinterModule { * @param value */ public final void printErrorString(final String value) { - this.error.print(value); + this.error.println(value); } } diff --git a/module/src/test/java/com/iluwatar/module/ModuleTest.java b/module/src/test/java/com/iluwatar/module/ModuleTest.java index 797e7f26a..cf3435850 100644 --- a/module/src/test/java/com/iluwatar/module/ModuleTest.java +++ b/module/src/test/java/com/iluwatar/module/ModuleTest.java @@ -24,19 +24,21 @@ import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.io.InputStreamReader; import org.apache.log4j.Logger; import org.junit.Test; /** - * The Data Mapper (DM) is a layer of software that separates the in-memory - * objects from the database. Its responsibility is to transfer data between the - * two and also to isolate them from each other. With Data Mapper the in-memory - * objects needn't know even that there's a database present; they need no SQL - * interface code, and certainly no knowledge of the database schema. (The - * database schema is always ignorant of the objects that use it.) Since it's a - * form of Mapper , Data Mapper itself is even unknown to the domain layer. + * 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 */ public class ModuleTest { @@ -54,23 +56,23 @@ public class ModuleTest { * @throws IOException */ @Test - public void testPositiveMessage() throws IOException { + public void positiveTestConsoleMessage() throws IOException { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final FileLoggerModule fileLoggerModule = FileLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + fileLoggerModule.prepare(); /* Print 'Message' in file */ - filePrinterModule.printString(MESSAGE); + fileLoggerModule.printString(MESSAGE); - /* Test if 'Message' is printed in file */ - assertEquals(readFirstLine(OUTPUT_FILE), MESSAGE); + /* Test if 'Message' is printed on console */ + assertEquals(readFirstLine(), MESSAGE); /* Unprepare to cleanup the modules */ - filePrinterModule.unprepare(); + fileLoggerModule.unprepare(); } /** @@ -79,20 +81,20 @@ public class ModuleTest { * @throws IOException */ @Test - public void testNegativeMessage() throws IOException { + public void negativeTestConsoleMessage() throws IOException { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + consoleLoggerModule.prepare(); - /* Test if nothing is printed in file */ - assertEquals(readFirstLine(OUTPUT_FILE), null); + /* Test if nothing is printed on console */ + assertEquals(readFirstLine(), null); /* Unprepare to cleanup the modules */ - filePrinterModule.unprepare(); + consoleLoggerModule.unprepare(); } /** @@ -101,23 +103,23 @@ public class ModuleTest { * @throws FileNotFoundException */ @Test - public void testPositiveErrorMessage() throws FileNotFoundException { + public void positiveTestConsoleErrorMessage() { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + consoleLoggerModule.prepare(); /* Print 'Error' in file */ - filePrinterModule.printErrorString(ERROR); + consoleLoggerModule.printErrorString(ERROR); - /* Test if 'Message' is printed in file */ - assertEquals(readFirstLine(ERROR_FILE), ERROR); + /* Test if 'Message' is printed on console */ + assertEquals(readFirstLine(), ERROR); /* Unprepare to cleanup the modules */ - filePrinterModule.unprepare(); + consoleLoggerModule.unprepare(); } /** @@ -126,20 +128,152 @@ public class ModuleTest { * @throws FileNotFoundException */ @Test - public void testNegativeErrorMessage() throws FileNotFoundException { + public void negativeTestConsoleErrorMessage() { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + consoleLoggerModule.prepare(); + + /* Test if nothing is printed on console */ + assertEquals(readFirstLine(), null); + + /* Unprepare to cleanup the modules */ + consoleLoggerModule.unprepare(); + } + + /** + * This test verify that 'MESSAGE' is perfectly printed in output file + * + * @throws IOException + */ + @Test + public void positiveTestFileMessage() throws IOException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FileLoggerModule 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 + */ + @Test + public void negativeTestFileMessage() throws IOException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FileLoggerModule fileLoggerModule = FileLoggerModule + .getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); + + /* Test if nothing is printed in file */ + assertEquals(readFirstLine(OUTPUT_FILE), null); + + /* Unprepare to cleanup the modules */ + fileLoggerModule.unprepare(); + } + + /** + * This test verify that 'ERROR' is perfectly printed in error file + * + * @throws FileNotFoundException + */ + @Test + public void positiveTestFileErrorMessage() throws FileNotFoundException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FileLoggerModule 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(readFirstLine(ERROR_FILE), ERROR); + + /* Unprepare to cleanup the modules */ + fileLoggerModule.unprepare(); + } + + /** + * This test verify that nothing is printed in error file + * + * @throws FileNotFoundException + */ + @Test + public void negativeTestFileErrorMessage() throws FileNotFoundException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + final FileLoggerModule fileLoggerModule = FileLoggerModule + .getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); /* Test if nothing is printed in file */ assertEquals(readFirstLine(ERROR_FILE), null); /* Unprepare to cleanup the modules */ - filePrinterModule.unprepare(); + fileLoggerModule.unprepare(); + } + + /** + * Utility method to read first line of a file + * + * @param file + * @return + */ + private static final String readFirstLine() { + + String firstLine = null; + BufferedReader bufferedReader = null; + try { + + /* Create a buffered reader */ + bufferedReader = new BufferedReader( + new InputStreamReader(System.in)); + + /* Read the line */ + firstLine = bufferedReader.readLine(); + + logger.info("ModuleTest::readFirstLineFromConsole() : firstLine : " + + firstLine); + + } catch (final IOException e) { + logger.error("ModuleTest::readFirstLineFromConsole()", e); + } finally { + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (final IOException e) { + logger.error("ModuleTest::readFirstLineFromConsole()", e); + } + } + } + + return firstLine; } /** @@ -160,17 +294,18 @@ public class ModuleTest { /* Read the line */ firstLine = bufferedReader.readLine(); - logger.info("ModuleTest::readFile() : firstLine : " + firstLine); + logger.info("ModuleTest::readFirstLine() : firstLine : " + + firstLine); } catch (final IOException e) { - logger.error("ModuleTest::readFile()", e); + logger.error("ModuleTest::readFirstLine()", e); } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (final IOException e) { - logger.error("ModuleTest::readFile()", e); + logger.error("ModuleTest::readFirstLine()", e); } } } From 1ace4c05d6c8141964285032edb17e136e0ba69f Mon Sep 17 00:00:00 2001 From: Amit Dixit Date: Thu, 27 Oct 2016 15:59:51 +0530 Subject: [PATCH 099/492] App++ App++ --- .../main/java/com/iluwatar/module/App.java | 19 +++++++++---------- .../java/com/iluwatar/module/AppTest.java | 1 - 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java index 0ca43d5c2..a3ecdb31c 100644 --- a/module/src/main/java/com/iluwatar/module/App.java +++ b/module/src/main/java/com/iluwatar/module/App.java @@ -21,16 +21,15 @@ package com.iluwatar.module; import java.io.FileNotFoundException; /** - * The Data Mapper (DM) is a layer of software that separates the in-memory - * objects from the database. Its responsibility is to transfer data between the - * two and also to isolate them from each other. With Data Mapper the in-memory - * objects needn't know even that there's a database present; they need no SQL - * interface code, and certainly no knowledge of the database schema. (The - * database schema is always ignorant of the objects that use it.) Since it's a - * form of Mapper , Data Mapper itself is even unknown to the domain layer. + * 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 basic CRUD operations: Create, Read, Update, - * and Delete. + * The below example demonstrates a use case for testing two different modules: + * File Logger and Console Logger * */ public final class App { @@ -39,7 +38,7 @@ public final class App { public static ConsoleLoggerModule consoleLoggerModule = null; public static void prepare() throws FileNotFoundException { - + fileLoggerModule = FileLoggerModule.getSingleton(); consoleLoggerModule = ConsoleLoggerModule.getSingleton(); diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java index 46c12ef38..eb348d758 100644 --- a/module/src/test/java/com/iluwatar/module/AppTest.java +++ b/module/src/test/java/com/iluwatar/module/AppTest.java @@ -25,7 +25,6 @@ import com.iluwatar.module.App; import org.junit.Test; /** - * Tests that Data-Mapper example runs without errors. */ public final class AppTest { From 7ba6cb43fdc38b534db583f7ec01e816b437f05d Mon Sep 17 00:00:00 2001 From: Amit Dixit Date: Thu, 27 Oct 2016 16:00:01 +0530 Subject: [PATCH 100/492] App App --- module/src/test/java/com/iluwatar/module/AppTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java index eb348d758..0f20b4959 100644 --- a/module/src/test/java/com/iluwatar/module/AppTest.java +++ b/module/src/test/java/com/iluwatar/module/AppTest.java @@ -25,6 +25,7 @@ import com.iluwatar.module.App; import org.junit.Test; /** + * Tests that Module example runs without errors. */ public final class AppTest { From ea7752c5e183d2981c29ce45bb4d989ef2eefab6 Mon Sep 17 00:00:00 2001 From: Amit Dixit Date: Thu, 27 Oct 2016 18:30:07 +0530 Subject: [PATCH 101/492] checkstyle errors removed checkstyle errors removed --- module/etc/module.urm.puml | 43 +++ .../main/java/com/iluwatar/module/App.java | 101 +++--- .../iluwatar/module/ConsoleLoggerModule.java | 122 +++---- .../com/iluwatar/module/FileLoggerModule.java | 151 +++++---- .../java/com/iluwatar/module/AppTest.java | 10 +- .../iluwatar/module/FileLoggerModuleTest.java | 182 ++++++++++ .../java/com/iluwatar/module/ModuleTest.java | 315 ------------------ 7 files changed, 425 insertions(+), 499 deletions(-) create mode 100644 module/etc/module.urm.puml create mode 100644 module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java delete mode 100644 module/src/test/java/com/iluwatar/module/ModuleTest.java diff --git a/module/etc/module.urm.puml b/module/etc/module.urm.puml new file mode 100644 index 000000000..d78f12da8 --- /dev/null +++ b/module/etc/module.urm.puml @@ -0,0 +1,43 @@ +@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() + + 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() + + 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/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java index a3ecdb31c..cfa50975f 100644 --- a/module/src/main/java/com/iluwatar/module/App.java +++ b/module/src/main/java/com/iluwatar/module/App.java @@ -21,64 +21,75 @@ 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 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 + * The below example demonstrates a use case for testing two different modules: File Logger and + * Console Logger * */ public final class App { - public static FileLoggerModule fileLoggerModule = null; - public static ConsoleLoggerModule consoleLoggerModule = null; + public static FileLoggerModule fileLoggerModule = null; + public static ConsoleLoggerModule consoleLoggerModule = null; - public static void prepare() throws FileNotFoundException { + /** + * 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 { - fileLoggerModule = FileLoggerModule.getSingleton(); - consoleLoggerModule = ConsoleLoggerModule.getSingleton(); + fileLoggerModule = FileLoggerModule.getSingleton(); + consoleLoggerModule = ConsoleLoggerModule.getSingleton(); - /* Prepare modules */ - fileLoggerModule.prepare(); - consoleLoggerModule.prepare(); - } + /* Prepare modules */ + fileLoggerModule.prepare(); + consoleLoggerModule.prepare(); + } - public static void unprepare() { + /** + * Following method performs the finalization + */ + public static void unprepare() { - /* Close all resources */ - fileLoggerModule.unprepare(); - consoleLoggerModule.unprepare(); - } + /* Close all resources */ + fileLoggerModule.unprepare(); + consoleLoggerModule.unprepare(); + } - public static final void execute(final String... args) { + /** + * Following method is main executor + * + * @param args for providing default program arguments + */ + public static void execute(final String... args) { - /* Send logs on file system */ - fileLoggerModule.printString("Message"); - fileLoggerModule.printErrorString("Error"); + /* Send logs on file system */ + fileLoggerModule.printString("Message"); + fileLoggerModule.printErrorString("Error"); - /* Send logs on console */ - consoleLoggerModule.printString("Message"); - consoleLoggerModule.printErrorString("Error"); - } + /* Send logs on console */ + consoleLoggerModule.printString("Message"); + consoleLoggerModule.printErrorString("Error"); + } - /** - * Program entry point. - * - * @param args - * command line args. - * @throws FileNotFoundException - */ - public static final void main(final String... args) - throws FileNotFoundException { - prepare(); - execute(args); - unprepare(); - } + /** + * 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(args); + unprepare(); + } - private App() { - } + private App() {} } diff --git a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java index 097f85b0e..8f5941951 100644 --- a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java +++ b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java @@ -18,89 +18,91 @@ */ package com.iluwatar.module; -import java.io.FileNotFoundException; import java.io.PrintStream; import org.apache.log4j.Logger; /** - * 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 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 Console logger module, which can print - * simple and error messages in two designated formats + * The below example demonstrates a Console logger module, which can print simple and error messages + * in two designated formats */ -public class ConsoleLoggerModule { +public final class ConsoleLoggerModule { - private static final Logger logger = Logger - .getLogger(ConsoleLoggerModule.class); + private static final Logger LOGGER = Logger.getLogger(ConsoleLoggerModule.class); - private static ConsoleLoggerModule singleton = null; + private static ConsoleLoggerModule singleton = null; - public PrintStream output = null; - public PrintStream error = null; + public PrintStream output = null; + public PrintStream error = null; - private ConsoleLoggerModule() { - } + private ConsoleLoggerModule() {} - public static final ConsoleLoggerModule getSingleton() { + /** + * 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(); - } + if (ConsoleLoggerModule.singleton == null) { + ConsoleLoggerModule.singleton = new ConsoleLoggerModule(); + } - return ConsoleLoggerModule.singleton; - } + return ConsoleLoggerModule.singleton; + } - /** - * - * @throws FileNotFoundException - */ - public final void prepare() { + /** + * Following method performs the initialization + */ + public void prepare() { - logger.debug("ConsoleLoggerModule::prepare();"); + LOGGER.debug("ConsoleLoggerModule::prepare();"); - this.output = new PrintStream(System.out); - this.error = new PrintStream(System.err); - } + this.output = new PrintStream(System.out); + this.error = new PrintStream(System.err); + } - /** - * - */ - public final void unprepare() { + /** + * Following method performs the finalization + */ + public void unprepare() { - if (this.output != null) { + if (this.output != null) { - this.output.flush(); - this.output.close(); - } + this.output.flush(); + this.output.close(); + } - if (this.error != null) { + if (this.error != null) { - this.error.flush(); - this.error.close(); - } + this.error.flush(); + this.error.close(); + } - logger.debug("ConsoleLoggerModule::unprepare();"); - } + LOGGER.debug("ConsoleLoggerModule::unprepare();"); + } - /** - * - * @param value - */ - public final void printString(final String value) { - this.output.println(value); - } + /** + * Used to print a message + * + * @param value will be printed on console + */ + public void printString(final String value) { + this.output.println(value); + } - /** - * - * @param value - */ - public final void printErrorString(final String value) { - this.error.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 index d1df062de..fae66191b 100644 --- a/module/src/main/java/com/iluwatar/module/FileLoggerModule.java +++ b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java @@ -1,23 +1,20 @@ /** * The MIT License Copyright (c) 2016 Amit Dixit * - * 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 + * 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 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. + * 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; @@ -28,86 +25,92 @@ import java.io.PrintStream; import org.apache.log4j.Logger; /** - * 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 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 File logger module, which can print simple - * and error messages in two designated files + * The below example demonstrates a File logger module, which can print simple and error messages in + * two designated files */ public final class FileLoggerModule { - private static final Logger logger = Logger - .getLogger(FileLoggerModule.class); + private static final Logger LOGGER = Logger.getLogger(FileLoggerModule.class); - private static FileLoggerModule singleton = null; + private static FileLoggerModule singleton = null; - private static final String OUTPUT_FILE = "output.txt"; - private static final String ERROR_FILE = "error.txt"; + private static final String OUTPUT_FILE = "output.txt"; + private static final String ERROR_FILE = "error.txt"; - public PrintStream output = null; - public PrintStream error = null; + public PrintStream output = null; + public PrintStream error = null; - private FileLoggerModule() { - } + private FileLoggerModule() {} - public static final FileLoggerModule getSingleton() { + /** + * 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(); - } + if (FileLoggerModule.singleton == null) { + FileLoggerModule.singleton = new FileLoggerModule(); + } - return FileLoggerModule.singleton; - } + return FileLoggerModule.singleton; + } - /** - * - * @throws FileNotFoundException - */ - public final void prepare() throws FileNotFoundException { + /** + * Following method performs the initialization + * + * @throws FileNotFoundException if program is not able to find log files (output.txt and + * error.txt) + */ + public void prepare() throws FileNotFoundException { - logger.debug("FileLoggerModule::prepare();"); + LOGGER.debug("FileLoggerModule::prepare();"); - this.output = new PrintStream(new FileOutputStream(OUTPUT_FILE)); - this.error = new PrintStream(new FileOutputStream(ERROR_FILE)); - } + this.output = new PrintStream(new FileOutputStream(OUTPUT_FILE)); + this.error = new PrintStream(new FileOutputStream(ERROR_FILE)); + } - /** - * - */ - public final void unprepare() { + /** + * Following method performs the finalization + */ + public void unprepare() { - if (this.output != null) { + if (this.output != null) { - this.output.flush(); - this.output.close(); - } + this.output.flush(); + this.output.close(); + } - if (this.error != null) { + if (this.error != null) { - this.error.flush(); - this.error.close(); - } + this.error.flush(); + this.error.close(); + } - logger.debug("FileLoggerModule::unprepare();"); - } + LOGGER.debug("FileLoggerModule::unprepare();"); + } - /** - * - * @param value - */ - public final void printString(final String value) { - this.output.println(value); - } + /** + * Used to print a message + * + * @param value will be printed in file + */ + public void printString(final String value) { + this.output.println(value); + } - /** - * - * @param value - */ - public final void printErrorString(final String value) { - this.error.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 index 0f20b4959..21b32407d 100644 --- a/module/src/test/java/com/iluwatar/module/AppTest.java +++ b/module/src/test/java/com/iluwatar/module/AppTest.java @@ -29,9 +29,9 @@ import org.junit.Test; */ public final class AppTest { - @Test - public void test() throws FileNotFoundException { - final String[] args = {}; - App.main(args); - } + @Test + public void test() throws FileNotFoundException { + final String[] args = {}; + App.main(args); + } } diff --git a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java new file mode 100644 index 000000000..ecefb307a --- /dev/null +++ b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java @@ -0,0 +1,182 @@ +/** + * The MIT License Copyright (c) 2016 Amit Dixit + * + * 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.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +import org.apache.log4j.Logger; +import org.junit.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 + */ +public final class FileLoggerModuleTest { + + private static final Logger LOGGER = Logger.getLogger(FileLoggerModuleTest.class); + + 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 + public void positiveTestFileMessage() throws IOException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule 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 + public void negativeTestFileMessage() throws IOException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule fileLoggerModule = FileLoggerModule.getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); + + /* Test if nothing is printed in file */ + assertEquals(readFirstLine(OUTPUT_FILE), null); + + /* 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 + public void positiveTestFileErrorMessage() throws FileNotFoundException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule 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(readFirstLine(ERROR_FILE), ERROR); + + /* Unprepare 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 + public void negativeTestFileErrorMessage() throws FileNotFoundException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule fileLoggerModule = FileLoggerModule.getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); + + /* Test if nothing is printed in file */ + assertEquals(readFirstLine(ERROR_FILE), null); + + /* 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 final String readFirstLine(final String file) { + + String firstLine = null; + BufferedReader bufferedReader = null; + try { + + /* Create a buffered reader */ + 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); + } finally { + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (final IOException e) { + LOGGER.error("ModuleTest::readFirstLine()", e); + } + } + } + + return firstLine; + } +} diff --git a/module/src/test/java/com/iluwatar/module/ModuleTest.java b/module/src/test/java/com/iluwatar/module/ModuleTest.java deleted file mode 100644 index cf3435850..000000000 --- a/module/src/test/java/com/iluwatar/module/ModuleTest.java +++ /dev/null @@ -1,315 +0,0 @@ -/** - * The MIT License Copyright (c) 2016 Amit Dixit - * - * 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.Assert.assertEquals; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; - -import org.apache.log4j.Logger; -import org.junit.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 - */ -public class ModuleTest { - - private static final Logger logger = Logger.getLogger(ModuleTest.class); - - 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 - */ - @Test - public void positiveTestConsoleMessage() throws IOException { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FileLoggerModule 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 on console */ - assertEquals(readFirstLine(), MESSAGE); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that nothing is printed in output file - * - * @throws IOException - */ - @Test - public void negativeTestConsoleMessage() throws IOException { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule - .getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - consoleLoggerModule.prepare(); - - /* Test if nothing is printed on console */ - assertEquals(readFirstLine(), null); - - /* Unprepare to cleanup the modules */ - consoleLoggerModule.unprepare(); - } - - /** - * This test verify that 'ERROR' is perfectly printed in error file - * - * @throws FileNotFoundException - */ - @Test - public void positiveTestConsoleErrorMessage() { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule - .getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - consoleLoggerModule.prepare(); - - /* Print 'Error' in file */ - consoleLoggerModule.printErrorString(ERROR); - - /* Test if 'Message' is printed on console */ - assertEquals(readFirstLine(), ERROR); - - /* Unprepare to cleanup the modules */ - consoleLoggerModule.unprepare(); - } - - /** - * This test verify that nothing is printed in error file - * - * @throws FileNotFoundException - */ - @Test - public void negativeTestConsoleErrorMessage() { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule - .getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - consoleLoggerModule.prepare(); - - /* Test if nothing is printed on console */ - assertEquals(readFirstLine(), null); - - /* Unprepare to cleanup the modules */ - consoleLoggerModule.unprepare(); - } - - /** - * This test verify that 'MESSAGE' is perfectly printed in output file - * - * @throws IOException - */ - @Test - public void positiveTestFileMessage() throws IOException { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FileLoggerModule 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 - */ - @Test - public void negativeTestFileMessage() throws IOException { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FileLoggerModule fileLoggerModule = FileLoggerModule - .getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Test if nothing is printed in file */ - assertEquals(readFirstLine(OUTPUT_FILE), null); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that 'ERROR' is perfectly printed in error file - * - * @throws FileNotFoundException - */ - @Test - public void positiveTestFileErrorMessage() throws FileNotFoundException { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FileLoggerModule 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(readFirstLine(ERROR_FILE), ERROR); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that nothing is printed in error file - * - * @throws FileNotFoundException - */ - @Test - public void negativeTestFileErrorMessage() throws FileNotFoundException { - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FileLoggerModule fileLoggerModule = FileLoggerModule - .getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Test if nothing is printed in file */ - assertEquals(readFirstLine(ERROR_FILE), null); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * Utility method to read first line of a file - * - * @param file - * @return - */ - private static final String readFirstLine() { - - String firstLine = null; - BufferedReader bufferedReader = null; - try { - - /* Create a buffered reader */ - bufferedReader = new BufferedReader( - new InputStreamReader(System.in)); - - /* Read the line */ - firstLine = bufferedReader.readLine(); - - logger.info("ModuleTest::readFirstLineFromConsole() : firstLine : " - + firstLine); - - } catch (final IOException e) { - logger.error("ModuleTest::readFirstLineFromConsole()", e); - } finally { - - if (bufferedReader != null) { - try { - bufferedReader.close(); - } catch (final IOException e) { - logger.error("ModuleTest::readFirstLineFromConsole()", e); - } - } - } - - return firstLine; - } - - /** - * Utility method to read first line of a file - * - * @param file - * @return - */ - private static final String readFirstLine(final String file) { - - String firstLine = null; - BufferedReader bufferedReader = null; - try { - - /* Create a buffered reader */ - bufferedReader = new BufferedReader(new FileReader(file)); - - /* Read the line */ - firstLine = bufferedReader.readLine(); - - logger.info("ModuleTest::readFirstLine() : firstLine : " - + firstLine); - - } catch (final IOException e) { - logger.error("ModuleTest::readFirstLine()", e); - } finally { - - if (bufferedReader != null) { - try { - bufferedReader.close(); - } catch (final IOException e) { - logger.error("ModuleTest::readFirstLine()", e); - } - } - } - - return firstLine; - } -} From 27d6d500bcc5cf31f59f2f6efe26271c30462b3a Mon Sep 17 00:00:00 2001 From: daniel-bryla Date: Fri, 28 Oct 2016 09:35:59 +0200 Subject: [PATCH 102/492] #502 Reverted changes in composite example, due to nature of this example using logger isn't good idea --- .../src/main/java/com/iluwatar/composite/Letter.java | 9 ++------- .../src/main/java/com/iluwatar/composite/Sentence.java | 9 ++------- composite/src/main/java/com/iluwatar/composite/Word.java | 9 ++------- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/composite/src/main/java/com/iluwatar/composite/Letter.java b/composite/src/main/java/com/iluwatar/composite/Letter.java index c8a6ccfce..088cdd44c 100644 --- a/composite/src/main/java/com/iluwatar/composite/Letter.java +++ b/composite/src/main/java/com/iluwatar/composite/Letter.java @@ -22,18 +22,13 @@ */ package com.iluwatar.composite; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - * + * * Letter * */ public class Letter extends LetterComposite { - private static final Logger LOGGER = LoggerFactory.getLogger(Letter.class); - private char c; public Letter(char c) { @@ -42,7 +37,7 @@ public class Letter extends LetterComposite { @Override protected void printThisBefore() { - LOGGER.info(String.valueOf(c)); + System.out.print(c); } @Override diff --git a/composite/src/main/java/com/iluwatar/composite/Sentence.java b/composite/src/main/java/com/iluwatar/composite/Sentence.java index ca8698f4f..bccf6c751 100644 --- a/composite/src/main/java/com/iluwatar/composite/Sentence.java +++ b/composite/src/main/java/com/iluwatar/composite/Sentence.java @@ -22,20 +22,15 @@ */ package com.iluwatar.composite; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.List; /** - * + * * Sentence * */ public class Sentence extends LetterComposite { - private static final Logger LOGGER = LoggerFactory.getLogger(Sentence.class); - /** * Constructor */ @@ -52,6 +47,6 @@ public class Sentence extends LetterComposite { @Override protected void printThisAfter() { - LOGGER.info("."); + System.out.print("."); } } diff --git a/composite/src/main/java/com/iluwatar/composite/Word.java b/composite/src/main/java/com/iluwatar/composite/Word.java index 4e5cfb31d..0174dc88a 100644 --- a/composite/src/main/java/com/iluwatar/composite/Word.java +++ b/composite/src/main/java/com/iluwatar/composite/Word.java @@ -22,20 +22,15 @@ */ package com.iluwatar.composite; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.List; /** - * + * * Word * */ public class Word extends LetterComposite { - private static final Logger LOGGER = LoggerFactory.getLogger(Word.class); - /** * Constructor */ @@ -47,7 +42,7 @@ public class Word extends LetterComposite { @Override protected void printThisBefore() { - LOGGER.info(" "); + System.out.print(" "); } @Override From 124fd33da07de5ea5e10a69a237cdce157cc5bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 1 Nov 2016 21:31:54 +0200 Subject: [PATCH 103/492] Remove use of coveralls-maven-plugin (sonarqube.com covers this) --- .travis.yml | 1 - README.md | 1 - pom.xml | 40 ---------------------------------------- 3 files changed, 42 deletions(-) diff --git a/.travis.yml b/.travis.yml index ba226ff5c..817b6635f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,6 @@ install: - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -e after_success: -- mvn clean test jacoco:report coveralls:report - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=$SONAR_TOKEN - bash update-ghpages.sh diff --git a/README.md b/README.md index 214fa91ff..6eed9561b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ # Design patterns implemented in Java [![Build status](https://travis-ci.org/iluwatar/java-design-patterns.svg?branch=master)](https://travis-ci.org/iluwatar/java-design-patterns) -[![Coverage Status](https://coveralls.io/repos/iluwatar/java-design-patterns/badge.svg?branch=master)](https://coveralls.io/r/iluwatar/java-design-patterns?branch=master) [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Quality Gate](https://sonarqube.com/api/badges/gate?key=com.iluwatar%3Ajava-design-patterns)](https://sonarqube.com/dashboard/index/com.iluwatar%3Ajava-design-patterns) diff --git a/pom.xml b/pom.xml index 538058a81..b8440f664 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,6 @@ 1.4.190 4.12 3.0 - 4.0.0 0.7.2.201409121644 1.4 2.16.1 @@ -320,29 +319,10 @@ 1.8 - - org.eluder.coveralls - coveralls-maven-plugin - ${coveralls.version} - - jb6wYzxkVvjolD6qOWpzWdcWBzYk2fAmF - - org.jacoco jacoco-maven-plugin ${jacoco.version} - - - - - domainapp/dom/modules/simple/QSimpleObject.class - **com.steadystate* - - prepare-agent @@ -378,26 +358,6 @@ - - - org.jacoco - jacoco-maven-plugin - 0.7.5.201505241946 - - - - prepare-agent - - - - report - prepare-package - - report - - - - org.apache.maven.plugins maven-surefire-plugin From e138163c4f1688678dc8bc43e9683b142d534fe7 Mon Sep 17 00:00:00 2001 From: daniel-bryla Date: Fri, 4 Nov 2016 11:47:06 +0100 Subject: [PATCH 104/492] #502 Adjusted tests for logger introduction --- .../com/iluwatar/decorator/TrollTest.java | 61 ++++++----- .../delegation/simple/DelegateTest.java | 55 ++++++++-- .../injection/AdvancedWizardTest.java | 30 ++++-- .../dependency/injection/GuiceWizardTest.java | 38 ++++--- .../injection/SimpleWizardTest.java | 25 ++++- .../dependency/injection/StdOutTest.java | 75 ------------- .../injection/utils/InMemoryAppender.java | 54 ++++++++++ .../doublechecked/locking/InventoryTest.java | 71 ++++++------ .../doubledispatch/CollisionTest.java | 54 +--------- .../event/aggregator/KingJoffreyTest.java | 67 +++++++----- .../facade/DwarvenGoldmineFacadeTest.java | 98 +++++++++-------- .../front/controller/CommandTest.java | 27 +++-- .../front/controller/FrontControllerTest.java | 27 +++-- .../iluwatar/front/controller/StdOutTest.java | 76 ------------- .../iluwatar/front/controller/ViewTest.java | 29 +++-- .../controller/utils/InMemoryAppender.java | 54 ++++++++++ .../hexagonal/service/ConsoleLottery.java | 1 - .../com/iluwatar/layers/CakeViewImplTest.java | 49 ++++++++- .../java/com/iluwatar/layers/StdOutTest.java | 78 -------------- .../iluwatar/mediator/PartyMemberTest.java | 84 ++++++++------- .../model/view/controller/GiantViewTest.java | 60 ++++++----- .../com/iluwatar/nullobject/NullNodeTest.java | 11 +- .../com/iluwatar/nullobject/StdOutTest.java | 76 ------------- .../com/iluwatar/nullobject/TreeTest.java | 68 +++++++++--- .../com/iluwatar/observer/StdOutTest.java | 76 ------------- .../observer/WeatherObserverTest.java | 29 +++-- .../com/iluwatar/observer/WeatherTest.java | 29 +++-- .../observer/generic/GWeatherTest.java | 37 ++++--- .../observer/generic/ObserverTest.java | 31 ++++-- .../observer/utils/InMemoryAppender.java | 58 ++++++++++ .../iluwatar/poison/pill/ConsumerTest.java | 54 ++++++++-- .../com/iluwatar/poison/pill/StdOutTest.java | 75 ------------- .../privateclassdata/ImmutableStewTest.java | 39 ++++--- .../iluwatar/privateclassdata/StdOutTest.java | 75 ------------- .../iluwatar/privateclassdata/StewTest.java | 27 +++-- .../utils/InMemoryAppender.java | 53 +++++++++ .../producer/consumer/ConsumerTest.java | 12 +-- .../producer/consumer/StdOutTest.java | 75 ------------- .../java/com/iluwatar/proxy/StdOutTest.java | 75 ------------- .../iluwatar/proxy/WizardTowerProxyTest.java | 35 ++++-- .../com/iluwatar/proxy/WizardTowerTest.java | 35 ++++-- .../proxy/utils/InMemoryAppender.java | 58 ++++++++++ .../writer/lock/ReaderAndWriterTest.java | 44 +++++--- .../reader/writer/lock/ReaderTest.java | 38 ++++--- .../reader/writer/lock/StdOutTest.java | 76 ------------- .../reader/writer/lock/WriterTest.java | 37 ++++--- .../writer/lock/utils/InMemoryAppender.java | 54 ++++++++++ .../is/initialization/ClosableTest.java | 56 ++++++++-- .../is/initialization/StdOutTest.java | 75 ------------- .../java/com/iluwatar/state/MammothTest.java | 76 +++++++------ .../strategy/DragonSlayingStrategyTest.java | 76 +++++++------ .../templatemethod/StealingMethodTest.java | 102 ++++++++++-------- .../java/com/iluwatar/twin/BallItemTest.java | 66 ++++++++++-- .../java/com/iluwatar/twin/StdOutTest.java | 75 ------------- .../java/com/iluwatar/visitor/StdOutTest.java | 75 ------------- .../com/iluwatar/visitor/VisitorTest.java | 58 ++++++++-- 56 files changed, 1447 insertions(+), 1602 deletions(-) delete mode 100644 dependency-injection/src/test/java/com/iluwatar/dependency/injection/StdOutTest.java create mode 100644 dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java delete mode 100644 front-controller/src/test/java/com/iluwatar/front/controller/StdOutTest.java create mode 100644 front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java delete mode 100644 layers/src/test/java/com/iluwatar/layers/StdOutTest.java delete mode 100644 null-object/src/test/java/com/iluwatar/nullobject/StdOutTest.java delete mode 100644 observer/src/test/java/com/iluwatar/observer/StdOutTest.java create mode 100644 observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java delete mode 100644 poison-pill/src/test/java/com/iluwatar/poison/pill/StdOutTest.java delete mode 100644 private-class-data/src/test/java/com/iluwatar/privateclassdata/StdOutTest.java create mode 100644 private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java delete mode 100644 producer-consumer/src/test/java/com/iluwatar/producer/consumer/StdOutTest.java delete mode 100644 proxy/src/test/java/com/iluwatar/proxy/StdOutTest.java create mode 100644 proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java delete mode 100644 reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/StdOutTest.java create mode 100644 reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java delete mode 100644 resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/StdOutTest.java delete mode 100644 twin/src/test/java/com/iluwatar/twin/StdOutTest.java delete mode 100644 visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java diff --git a/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java index 84b0f6d20..652c1fcdc 100644 --- a/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java +++ b/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java @@ -22,16 +22,18 @@ */ package com.iluwatar.decorator; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; +import java.util.LinkedList; +import java.util.List; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; -import static org.mockito.internal.verification.VerificationModeFactory.times; /** * Date: 12/7/15 - 7:26 PM @@ -40,31 +42,16 @@ import static org.mockito.internal.verification.VerificationModeFactory.times; */ public class TrollTest { - /** - * The mocked standard out stream, required since the actions don't have any influence on other - * objects, except for writing to the std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); + private InMemoryAppender appender; - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ @Before public void setUp() { - System.setOut(this.stdOutMock); + appender = new InMemoryAppender(Troll.class); } - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ @After public void tearDown() { - System.setOut(this.stdOutOrig); + appender.stop(); } @Test @@ -73,12 +60,34 @@ public class TrollTest { assertEquals(10, troll.getAttackPower()); troll.attack(); - verify(this.stdOutMock, times(1)).println(eq("The troll swings at you with a club!")); + assertEquals("The troll swings at you with a club!", appender.getLastMessage()); troll.fleeBattle(); - verify(this.stdOutMock, times(1)).println(eq("The troll shrieks in horror and runs away!")); + assertEquals("The troll shrieks in horror and runs away!", appender.getLastMessage()); - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(2, appender.getLogSize()); } -} \ No newline at end of file + private class InMemoryAppender extends AppenderBase { + + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getMessage(); + } + + public int getLogSize() { + return log.size(); + } + } +} diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java index 6a19c9a1a..c1f32a8e0 100644 --- a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java +++ b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java @@ -22,28 +22,44 @@ */ package com.iluwatar.delegation.simple; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import com.iluwatar.delegation.simple.printers.CanonPrinter; import com.iluwatar.delegation.simple.printers.EpsonPrinter; import com.iluwatar.delegation.simple.printers.HpPrinter; -import org.junit.Rule; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemOutRule; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; import static org.junit.Assert.assertEquals; public class DelegateTest { - private static final String MESSAGE = "Test Message Printed"; + private InMemoryAppender appender; - @Rule - public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } + + private static final String MESSAGE = "Test Message Printed"; @Test public void testCanonPrinter() throws Exception { PrinterController printerController = new PrinterController(new CanonPrinter()); printerController.print(MESSAGE); - assertEquals("Canon Printer : Test Message Printed", systemOutRule.getLog()); + assertEquals("Canon Printer : Test Message Printed", appender.getLastMessage()); } @Test @@ -51,7 +67,7 @@ public class DelegateTest { PrinterController printerController = new PrinterController(new HpPrinter()); printerController.print(MESSAGE); - assertEquals("HP Printer : Test Message Printed", systemOutRule.getLog()); + assertEquals("HP Printer : Test Message Printed", appender.getLastMessage()); } @Test @@ -59,7 +75,30 @@ public class DelegateTest { PrinterController printerController = new PrinterController(new EpsonPrinter()); printerController.print(MESSAGE); - assertEquals("Epson Printer : Test Message Printed", systemOutRule.getLog()); + assertEquals("Epson Printer : Test Message Printed", appender.getLastMessage()); + } + + private class InMemoryAppender extends AppenderBase { + + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + + public int getLogSize() { + return log.size(); + } } } diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedWizardTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedWizardTest.java index d1f5e574c..a0578626f 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedWizardTest.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedWizardTest.java @@ -22,18 +22,31 @@ */ package com.iluwatar.dependency.injection; +import com.iluwatar.dependency.injection.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/10/15 - 8:40 PM * * @author Jeroen Meulemeester */ -public class AdvancedWizardTest extends StdOutTest { +public class AdvancedWizardTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Tobacco.class); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Test if the {@link AdvancedWizard} smokes whatever instance of {@link Tobacco} is passed to him @@ -51,12 +64,13 @@ public class AdvancedWizardTest extends StdOutTest { advancedWizard.smoke(); // Verify if the wizard is smoking the correct tobacco ... - verify(getStdOutMock(), times(1)).println("AdvancedWizard smoking " + tobacco.getClass().getSimpleName()); + assertEquals("AdvancedWizard smoking " + tobacco.getClass().getSimpleName(), appender.getLastMessage()); - // ... and nothing else is happening. - verifyNoMoreInteractions(getStdOutMock()); } + // ... and nothing else is happening. + assertEquals(tobaccos.length, appender.getLogSize()); + } -} \ No newline at end of file +} diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/GuiceWizardTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/GuiceWizardTest.java index 1d3d679df..811773678 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/GuiceWizardTest.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/GuiceWizardTest.java @@ -25,19 +25,31 @@ package com.iluwatar.dependency.injection; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; - +import com.iluwatar.dependency.injection.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/10/15 - 8:57 PM * * @author Jeroen Meulemeester */ -public class GuiceWizardTest extends StdOutTest { +public class GuiceWizardTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Tobacco.class); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Test if the {@link GuiceWizard} smokes whatever instance of {@link Tobacco} is passed to him @@ -55,12 +67,11 @@ public class GuiceWizardTest extends StdOutTest { guiceWizard.smoke(); // Verify if the wizard is smoking the correct tobacco ... - verify(getStdOutMock(), times(1)).println("GuiceWizard smoking " + tobacco.getClass().getSimpleName()); - - // ... and nothing else is happening. - verifyNoMoreInteractions(getStdOutMock()); + assertEquals("GuiceWizard smoking " + tobacco.getClass().getSimpleName(), appender.getLastMessage()); } + // ... and nothing else is happening. + assertEquals(tobaccos.length, appender.getLogSize()); } /** @@ -89,12 +100,11 @@ public class GuiceWizardTest extends StdOutTest { guiceWizard.smoke(); // Verify if the wizard is smoking the correct tobacco ... - verify(getStdOutMock(), times(1)).println("GuiceWizard smoking " + tobaccoClass.getSimpleName()); - - // ... and nothing else is happening. - verifyNoMoreInteractions(getStdOutMock()); + assertEquals("GuiceWizard smoking " + tobaccoClass.getSimpleName(), appender.getLastMessage()); } + // ... and nothing else is happening. + assertEquals(tobaccos.length, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java index e5a856e8d..cda3eac47 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java @@ -22,16 +22,31 @@ */ package com.iluwatar.dependency.injection; +import com.iluwatar.dependency.injection.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; /** * Date: 12/10/15 - 8:26 PM * * @author Jeroen Meulemeester */ -public class SimpleWizardTest extends StdOutTest { +public class SimpleWizardTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Tobacco.class); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Test if the {@link SimpleWizard} does the only thing it can do: Smoke it's {@link @@ -41,8 +56,8 @@ public class SimpleWizardTest extends StdOutTest { public void testSmoke() { final SimpleWizard simpleWizard = new SimpleWizard(); simpleWizard.smoke(); - verify(getStdOutMock(), times(1)).println("SimpleWizard smoking OldTobyTobacco"); - verifyNoMoreInteractions(getStdOutMock()); + assertEquals("SimpleWizard smoking OldTobyTobacco", appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/StdOutTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/StdOutTest.java deleted file mode 100644 index 57272c511..000000000 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.dependency.injection; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since the actions of the wizard don't - * have any influence on any other accessible objects, except for writing to std-out using {@link - * System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } -} diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java new file mode 100644 index 000000000..b4c60b8aa --- /dev/null +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright (c) 2014 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.dependency.injection.utils; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; + +public class InMemoryAppender extends AppenderBase { + + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + + public int getLogSize() { + return log.size(); + } +} diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java index 485c9573e..9f5f608b0 100644 --- a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java +++ b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java @@ -22,24 +22,23 @@ */ package com.iluwatar.doublechecked.locking; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.junit.Assert.assertTrue; /** * Date: 12/10/15 - 9:34 PM @@ -48,31 +47,16 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; */ public class InventoryTest { - /** - * The mocked standard out {@link PrintStream}, used to verify a steady increasing size of the - * {@link Inventory} while adding items from multiple threads concurrently - */ - private final PrintStream stdOutMock = mock(PrintStream.class); + private InMemoryAppender appender; - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ @Before public void setUp() { - System.setOut(this.stdOutMock); + appender = new InMemoryAppender(Inventory.class); } - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ @After public void tearDown() { - System.setOut(this.stdOutOrig); + appender.stop(); } /** @@ -112,21 +96,32 @@ public class InventoryTest { assertNotNull(items); assertEquals(INVENTORY_SIZE, items.size()); - // Capture all stdOut messages ... - final ArgumentCaptor stdOutCaptor = ArgumentCaptor.forClass(String.class); - verify(this.stdOutMock, times(INVENTORY_SIZE)).println(stdOutCaptor.capture()); - - // ... verify if we got all 1000 - final List values = stdOutCaptor.getAllValues(); - assertEquals(INVENTORY_SIZE, values.size()); + assertEquals(INVENTORY_SIZE, appender.getLogSize()); // ... and check if the inventory size is increasing continuously - for (int i = 0; i < values.size(); i++) { - assertNotNull(values.get(i)); - assertTrue(values.get(i).contains("items.size()=" + (i + 1))); + for (int i = 0; i < items.size(); i++) { + assertTrue(appender.log.get(i).getFormattedMessage().contains("items.size()=" + (i + 1))); } - - verifyNoMoreInteractions(this.stdOutMock); } -} \ No newline at end of file + + + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + } + +} diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java index dbc8fc55e..6576d6d2f 100644 --- a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java +++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java @@ -22,17 +22,9 @@ */ package com.iluwatar.doubledispatch; -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; import java.util.Objects; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; /** * Date: 12/10/15 - 8:37 PM @@ -41,43 +33,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; */ public abstract class CollisionTest { - /** - * The mocked standard out {@link PrintStream}, required if some of the actions on the tested - * object don't have a direct influence on any other accessible objects, except for writing to - * std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - /** * Get the tested object * @@ -106,9 +61,6 @@ public abstract class CollisionTest { tested.collision(other); - verify(getStdOutMock(), times(1)).println(description); - verifyNoMoreInteractions(getStdOutMock()); - testOnFire(other, tested, otherOnFire); testDamaged(other, tested, otherDamaged); @@ -129,8 +81,8 @@ public abstract class CollisionTest { final String targetName = target.getClass().getSimpleName(); final String otherName = other.getClass().getSimpleName(); - final String errorMessage = expectTargetOnFire - ? "Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!" + final String errorMessage = expectTargetOnFire + ? "Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!" : "Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!"; assertEquals(errorMessage, expectTargetOnFire, target.isOnFire()); @@ -149,7 +101,7 @@ public abstract class CollisionTest { final String otherName = other.getClass().getSimpleName(); final String errorMessage = expectedDamage - ? "Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!" + ? "Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!" : "Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!"; assertEquals(errorMessage, expectedDamage, target.isDamaged()); diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java index 3e0028ac4..e06d10b6a 100644 --- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java +++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java @@ -22,17 +22,18 @@ */ package com.iluwatar.event.aggregator; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; +import java.util.LinkedList; +import java.util.List; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/12/15 - 3:04 PM @@ -41,31 +42,16 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; */ public class KingJoffreyTest { - /** - * The mocked standard out {@link PrintStream}, required since {@link KingJoffrey} does nothing - * except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); + private InMemoryAppender appender; - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ @Before public void setUp() { - System.setOut(this.stdOutMock); + appender = new InMemoryAppender(KingJoffrey.class); } - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ @After public void tearDown() { - System.setOut(this.stdOutOrig); + appender.stop(); } /** @@ -75,15 +61,38 @@ public class KingJoffreyTest { public void testOnEvent() { final KingJoffrey kingJoffrey = new KingJoffrey(); - for (final Event event : Event.values()) { - verifyZeroInteractions(this.stdOutMock); + for (int i = 0; i < Event.values().length; ++i) { + assertEquals(i, appender.getLogSize()); + Event event = Event.values()[i]; kingJoffrey.onEvent(event); final String expectedMessage = "Received event from the King's Hand: " + event.toString(); - verify(this.stdOutMock, times(1)).println(expectedMessage); - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(expectedMessage, appender.getLastMessage()); + assertEquals(i + 1, appender.getLogSize()); } } -} \ No newline at end of file + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + + public int getLogSize() { + return log.size(); + } + } + +} diff --git a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java index 4a3b218e2..7718f7d41 100644 --- a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java +++ b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java @@ -22,17 +22,19 @@ */ package com.iluwatar.facade; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; +import java.util.LinkedList; +import java.util.List; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.internal.verification.VerificationModeFactory.times; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Date: 12/9/15 - 9:40 PM @@ -41,35 +43,19 @@ import static org.mockito.internal.verification.VerificationModeFactory.times; */ public class DwarvenGoldmineFacadeTest { - /** - * The mocked standard out {@link PrintStream}, required since the actions on the gold mine facade - * don't have any influence on any other accessible objects, except for writing to std-out using - * {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); + private InMemoryAppender appender; - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ @Before public void setUp() { - System.setOut(this.stdOutMock); + appender = new InMemoryAppender(); } - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ @After public void tearDown() { - System.setOut(this.stdOutOrig); + appender.stop(); } - /** + /** * Test a complete day cycle in the gold mine by executing all three different steps: {@link * DwarvenGoldmineFacade#startNewDay()}, {@link DwarvenGoldmineFacade#digOutGold()} and {@link * DwarvenGoldmineFacade#endDay()}. @@ -82,44 +68,68 @@ public class DwarvenGoldmineFacadeTest { goldMine.startNewDay(); // On the start of a day, all workers should wake up ... - verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger wakes up.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator wakes up.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger wakes up.")); + assertTrue(appender.logContains("Dwarf gold digger wakes up.")); + assertTrue(appender.logContains("Dwarf cart operator wakes up.")); + assertTrue(appender.logContains("Dwarven tunnel digger wakes up.")); // ... and go to the mine - verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger goes to the mine.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator goes to the mine.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger goes to the mine.")); + assertTrue(appender.logContains("Dwarf gold digger goes to the mine.")); + assertTrue(appender.logContains("Dwarf cart operator goes to the mine.")); + assertTrue(appender.logContains("Dwarven tunnel digger goes to the mine.")); // No other actions were invoked, so the workers shouldn't have done (printed) anything else - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(6, appender.getLogSize()); // Now do some actual work, start digging gold! goldMine.digOutGold(); // Since we gave the dig command, every worker should be doing it's job ... - verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger digs for gold.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator moves gold chunks out of the mine.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger creates another promising tunnel.")); + assertTrue(appender.logContains("Dwarf gold digger digs for gold.")); + assertTrue(appender.logContains("Dwarf cart operator moves gold chunks out of the mine.")); + assertTrue(appender.logContains("Dwarven tunnel digger creates another promising tunnel.")); // Again, they shouldn't be doing anything else. - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(9, appender.getLogSize()); // Enough gold, lets end the day. goldMine.endDay(); // Check if the workers go home ... - verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger goes home.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator goes home.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger goes home.")); + assertTrue(appender.logContains("Dwarf gold digger goes home.")); + assertTrue(appender.logContains("Dwarf cart operator goes home.")); + assertTrue(appender.logContains("Dwarven tunnel digger goes home.")); // ... and go to sleep. We need well rested workers the next day :) - verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger goes to sleep.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator goes to sleep.")); - verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger goes to sleep.")); + assertTrue(appender.logContains("Dwarf gold digger goes to sleep.")); + assertTrue(appender.logContains("Dwarf cart operator goes to sleep.")); + assertTrue(appender.logContains("Dwarven tunnel digger goes to sleep.")); // Every worker should be sleeping now, no other actions allowed - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(15, appender.getLogSize()); } + private class InMemoryAppender extends AppenderBase { + + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + + public boolean logContains(String message) { + return log.stream().anyMatch(event -> event.getFormattedMessage().equals(message)); + } + } + + } diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/CommandTest.java b/front-controller/src/test/java/com/iluwatar/front/controller/CommandTest.java index c4d9ae625..0b5c9f593 100644 --- a/front-controller/src/test/java/com/iluwatar/front/controller/CommandTest.java +++ b/front-controller/src/test/java/com/iluwatar/front/controller/CommandTest.java @@ -22,6 +22,9 @@ */ package com.iluwatar.front.controller; +import com.iluwatar.front.controller.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -30,9 +33,7 @@ import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.List; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/13/15 - 1:39 PM @@ -40,7 +41,19 @@ import static org.mockito.Mockito.verifyZeroInteractions; * @author Jeroen Meulemeester */ @RunWith(Parameterized.class) -public class CommandTest extends StdOutTest { +public class CommandTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } @Parameters public static List data() { @@ -75,10 +88,10 @@ public class CommandTest extends StdOutTest { @Test public void testDisplay() { final FrontController frontController = new FrontController(); - verifyZeroInteractions(getStdOutMock()); + assertEquals(0, appender.getLogSize()); frontController.handleRequest(request); - verify(getStdOutMock()).println(displayMessage); - verifyNoMoreInteractions(getStdOutMock()); + assertEquals(displayMessage, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } } diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/FrontControllerTest.java b/front-controller/src/test/java/com/iluwatar/front/controller/FrontControllerTest.java index 0822ffcd0..46a26e6fb 100644 --- a/front-controller/src/test/java/com/iluwatar/front/controller/FrontControllerTest.java +++ b/front-controller/src/test/java/com/iluwatar/front/controller/FrontControllerTest.java @@ -22,6 +22,9 @@ */ package com.iluwatar.front.controller; +import com.iluwatar.front.controller.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -30,9 +33,7 @@ import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.List; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/13/15 - 1:39 PM @@ -40,7 +41,19 @@ import static org.mockito.Mockito.verifyZeroInteractions; * @author Jeroen Meulemeester */ @RunWith(Parameterized.class) -public class FrontControllerTest extends StdOutTest { +public class FrontControllerTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } @Parameters public static List data() { @@ -74,10 +87,10 @@ public class FrontControllerTest extends StdOutTest { @Test public void testDisplay() { - verifyZeroInteractions(getStdOutMock()); + assertEquals(0, appender.getLogSize()); this.command.process(); - verify(getStdOutMock()).println(displayMessage); - verifyNoMoreInteractions(getStdOutMock()); + assertEquals(displayMessage, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } } diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/StdOutTest.java b/front-controller/src/test/java/com/iluwatar/front/controller/StdOutTest.java deleted file mode 100644 index bc32a1b3c..000000000 --- a/front-controller/src/test/java/com/iluwatar/front/controller/StdOutTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.front.controller; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since the actions of the views don't have - * any influence on any other accessible objects, except for writing to std-out using {@link - * System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/ViewTest.java b/front-controller/src/test/java/com/iluwatar/front/controller/ViewTest.java index cdabd66ef..bca070305 100644 --- a/front-controller/src/test/java/com/iluwatar/front/controller/ViewTest.java +++ b/front-controller/src/test/java/com/iluwatar/front/controller/ViewTest.java @@ -22,6 +22,9 @@ */ package com.iluwatar.front.controller; +import com.iluwatar.front.controller.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -30,9 +33,7 @@ import org.junit.runners.Parameterized.Parameters; import java.util.ArrayList; import java.util.List; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/13/15 - 1:39 PM @@ -40,7 +41,19 @@ import static org.mockito.Mockito.verifyZeroInteractions; * @author Jeroen Meulemeester */ @RunWith(Parameterized.class) -public class ViewTest extends StdOutTest { +public class ViewTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } @Parameters public static List data() { @@ -74,10 +87,10 @@ public class ViewTest extends StdOutTest { @Test public void testDisplay() { - verifyZeroInteractions(getStdOutMock()); + assertEquals(0, appender.getLogSize()); this.view.display(); - verify(getStdOutMock()).println(displayMessage); - verifyNoMoreInteractions(getStdOutMock()); + assertEquals(displayMessage, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java b/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java new file mode 100644 index 000000000..1747deac5 --- /dev/null +++ b/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright (c) 2014 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.front.controller.utils; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; + +public class InMemoryAppender extends AppenderBase { + + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + + public int getLogSize() { + return log.size(); + } +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java index 00d61b668..077b0f235 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/service/ConsoleLottery.java @@ -24,7 +24,6 @@ package com.iluwatar.hexagonal.service; import com.google.inject.Guice; import com.google.inject.Injector; -import com.iluwatar.hexagonal.administration.ConsoleAdministration; import com.iluwatar.hexagonal.banking.WireTransfers; import com.iluwatar.hexagonal.domain.LotteryNumbers; import com.iluwatar.hexagonal.domain.LotteryService; diff --git a/layers/src/test/java/com/iluwatar/layers/CakeViewImplTest.java b/layers/src/test/java/com/iluwatar/layers/CakeViewImplTest.java index a69aa23bb..3a9214ae1 100644 --- a/layers/src/test/java/com/iluwatar/layers/CakeViewImplTest.java +++ b/layers/src/test/java/com/iluwatar/layers/CakeViewImplTest.java @@ -22,11 +22,19 @@ */ package com.iluwatar.layers; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; /** @@ -34,7 +42,19 @@ import static org.mockito.Mockito.*; * * @author Jeroen Meulemeester */ -public class CakeViewImplTest extends StdOutTest { +public class CakeViewImplTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(CakeViewImpl.class); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Verify if the cake view renders the expected result @@ -56,11 +76,34 @@ public class CakeViewImplTest extends StdOutTest { final CakeViewImpl cakeView = new CakeViewImpl(bakingService); - verifyZeroInteractions(getStdOutMock()); + assertEquals(0, appender.getLogSize()); cakeView.render(); - verify(getStdOutMock(), times(1)).println(cake); + assertEquals(cake.toString(), appender.getLastMessage()); } + private class InMemoryAppender extends AppenderBase { + + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + + public int getLogSize() { + return log.size(); + } + } + } diff --git a/layers/src/test/java/com/iluwatar/layers/StdOutTest.java b/layers/src/test/java/com/iluwatar/layers/StdOutTest.java deleted file mode 100644 index 67a554873..000000000 --- a/layers/src/test/java/com/iluwatar/layers/StdOutTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.layers; - -import org.junit.After; -import org.junit.Before; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since the actions of the views don't have - * any influence on any other accessible objects, except for writing to std-out using {@link - * System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java index 0bf43f9cd..e5f7e2719 100644 --- a/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java +++ b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java @@ -22,22 +22,25 @@ */ package com.iluwatar.mediator; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; import java.util.Arrays; import java.util.Collection; +import java.util.LinkedList; +import java.util.List; import java.util.function.Supplier; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; /** * Date: 12/19/15 - 10:13 PM @@ -57,34 +60,6 @@ public class PartyMemberTest { ); } - /** - * The mocked standard out {@link PrintStream}, required since some actions on a {@link - * PartyMember} have any influence on any other accessible objects, except for writing to std-out - * using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - /** * The factory, used to create a new instance of the tested party member */ @@ -99,6 +74,18 @@ public class PartyMemberTest { this.memberSupplier = memberSupplier; } + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(PartyMemberBase.class); + } + + @After + public void tearDown() { + appender.stop(); + } + /** * Verify if a party action triggers the correct output to the std-Out */ @@ -108,10 +95,10 @@ public class PartyMemberTest { for (final Action action : Action.values()) { member.partyAction(action); - verify(this.stdOutMock).println(member.toString() + " " + action.getDescription()); + assertEquals(member.toString() + " " + action.getDescription(), appender.getLastMessage()); } - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(Action.values().length, appender.getLogSize()); } /** @@ -122,19 +109,19 @@ public class PartyMemberTest { final PartyMember member = this.memberSupplier.get(); member.act(Action.GOLD); - verifyZeroInteractions(this.stdOutMock); + assertEquals(0, appender.getLogSize()); final Party party = mock(Party.class); member.joinedParty(party); - verify(this.stdOutMock).println(member.toString() + " joins the party"); + assertEquals(member.toString() + " joins the party", appender.getLastMessage()); for (final Action action : Action.values()) { member.act(action); - verify(this.stdOutMock).println(member.toString() + " " + action.toString()); + assertEquals(member.toString() + " " + action.toString(), appender.getLastMessage()); verify(party).act(member, action); } - verifyNoMoreInteractions(party, this.stdOutMock); + assertEquals(Action.values().length + 1, appender.getLogSize()); } /** @@ -147,4 +134,27 @@ public class PartyMemberTest { assertEquals(memberClass.getSimpleName(), member.toString()); } + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + } + + } diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java index 89d503d4e..9ea0ae96e 100644 --- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java +++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java @@ -22,15 +22,19 @@ */ package com.iluwatar.model.view.controller; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; +import java.util.LinkedList; +import java.util.List; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; /** * Date: 12/20/15 - 2:04 PM @@ -39,32 +43,16 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; */ public class GiantViewTest { - /** - * The mocked standard out {@link PrintStream}, required since the actions of the views don't have - * any influence on any other accessible objects, except for writing to std-out using {@link - * System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); + private InMemoryAppender appender; - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ @Before public void setUp() { - System.setOut(this.stdOutMock); + appender = new InMemoryAppender(GiantView.class); } - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ @After public void tearDown() { - System.setOut(this.stdOutOrig); + appender.stop(); } /** @@ -78,9 +66,29 @@ public class GiantViewTest { final GiantModel model = mock(GiantModel.class); view.displayGiant(model); - verify(this.stdOutMock).println(model); - verifyNoMoreInteractions(model, this.stdOutMock); - + assertEquals(model.toString(), appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } -} \ No newline at end of file + public class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getMessage(); + } + + public int getLogSize() { + return log.size(); + } + } +} diff --git a/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java b/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java index 1375b8949..98168fc0a 100644 --- a/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java +++ b/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java @@ -23,19 +23,15 @@ package com.iluwatar.nullobject; import org.junit.Test; -import org.mockito.Mockito; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; +import static org.junit.Assert.*; /** * Date: 12/26/15 - 11:47 PM * * @author Jeroen Meulemeester */ -public class NullNodeTest extends StdOutTest { +public class NullNodeTest { /** * Verify if {@link NullNode#getInstance()} actually returns the same object instance @@ -59,7 +55,6 @@ public class NullNodeTest extends StdOutTest { @Test public void testWalk() throws Exception { NullNode.getInstance().walk(); - Mockito.verifyZeroInteractions(getStdOutMock()); } -} \ No newline at end of file +} diff --git a/null-object/src/test/java/com/iluwatar/nullobject/StdOutTest.java b/null-object/src/test/java/com/iluwatar/nullobject/StdOutTest.java deleted file mode 100644 index 0c0122132..000000000 --- a/null-object/src/test/java/com/iluwatar/nullobject/StdOutTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.nullobject; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since walking through the tree has no - * influence on any other accessible object, except for writing to std-out using {@link - * System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java index 6c77cd236..2712b0356 100644 --- a/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java +++ b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java @@ -22,20 +22,37 @@ */ package com.iluwatar.nullobject; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; +import org.slf4j.LoggerFactory; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; +import java.util.LinkedList; +import java.util.List; + +import static org.junit.Assert.*; /** * Date: 12/26/15 - 11:44 PM * * @author Jeroen Meulemeester */ -public class TreeTest extends StdOutTest { +public class TreeTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } /** * During the tests, the same tree structure will be used, shown below. End points will be @@ -79,15 +96,14 @@ public class TreeTest extends StdOutTest { public void testWalk() { TREE_ROOT.walk(); - final InOrder inOrder = Mockito.inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("root"); - inOrder.verify(getStdOutMock()).println("level1_a"); - inOrder.verify(getStdOutMock()).println("level2_a"); - inOrder.verify(getStdOutMock()).println("level3_a"); - inOrder.verify(getStdOutMock()).println("level3_b"); - inOrder.verify(getStdOutMock()).println("level2_b"); - inOrder.verify(getStdOutMock()).println("level1_b"); - inOrder.verifyNoMoreInteractions(); + assertTrue(appender.logContains("root")); + assertTrue(appender.logContains("level1_a")); + assertTrue(appender.logContains("level2_a")); + assertTrue(appender.logContains("level3_a")); + assertTrue(appender.logContains("level3_b")); + assertTrue(appender.logContains("level2_b")); + assertTrue(appender.logContains("level1_b")); + assertEquals(7, appender.getLogSize()); } @Test @@ -120,4 +136,26 @@ public class TreeTest extends StdOutTest { assertSame(NullNode.getInstance(), level1.getLeft()); } + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + 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.getMessage().equals(message)); + } + + public int getLogSize() { + return log.size(); + } + } + } diff --git a/observer/src/test/java/com/iluwatar/observer/StdOutTest.java b/observer/src/test/java/com/iluwatar/observer/StdOutTest.java deleted file mode 100644 index afd870ae4..000000000 --- a/observer/src/test/java/com/iluwatar/observer/StdOutTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.observer; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/27/15 - 12:16 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since changes in the weather doesn't has - * any influence on any other accessible objects, except for writing to std-out using {@link - * System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - protected final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java index a06c19952..1ccf4bf12 100644 --- a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java +++ b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java @@ -22,20 +22,33 @@ */ package com.iluwatar.observer; +import com.iluwatar.observer.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import java.util.function.Supplier; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/27/15 - 11:44 AM * * @author Jeroen Meulemeester */ -public abstract class WeatherObserverTest extends StdOutTest { +public abstract class WeatherObserverTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } /** * The observer instance factory @@ -71,11 +84,11 @@ public abstract class WeatherObserverTest extends Std @Test public void testObserver() { final O observer = this.factory.get(); - verifyZeroInteractions(getStdOutMock()); + assertEquals(0, appender.getLogSize()); observer.update(this.weather); - verify(getStdOutMock()).println(this.response); - verifyNoMoreInteractions(getStdOutMock()); + assertEquals(response, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/observer/src/test/java/com/iluwatar/observer/WeatherTest.java b/observer/src/test/java/com/iluwatar/observer/WeatherTest.java index 7a38e7137..9d53b2e23 100644 --- a/observer/src/test/java/com/iluwatar/observer/WeatherTest.java +++ b/observer/src/test/java/com/iluwatar/observer/WeatherTest.java @@ -22,9 +22,13 @@ */ package com.iluwatar.observer; +import com.iluwatar.observer.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -36,7 +40,19 @@ import static org.mockito.Mockito.verifyZeroInteractions; * * @author Jeroen Meulemeester */ -public class WeatherTest extends StdOutTest { +public class WeatherTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Weather.class); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Add a {@link WeatherObserver}, verify if it gets notified of a weather change, remove the @@ -51,14 +67,15 @@ public class WeatherTest extends StdOutTest { verifyZeroInteractions(observer); weather.timePasses(); - verify(getStdOutMock()).println("The weather changed to rainy."); + assertEquals("The weather changed to rainy.", appender.getLastMessage()); verify(observer).update(WeatherType.RAINY); weather.removeObserver(observer); weather.timePasses(); - verify(getStdOutMock()).println("The weather changed to windy."); + assertEquals("The weather changed to windy.", appender.getLastMessage()); - verifyNoMoreInteractions(observer, getStdOutMock()); + verifyNoMoreInteractions(observer); + assertEquals(2, appender.getLogSize()); } /** @@ -70,7 +87,7 @@ public class WeatherTest extends StdOutTest { final Weather weather = new Weather(); weather.addObserver(observer); - final InOrder inOrder = inOrder(observer, getStdOutMock()); + final InOrder inOrder = inOrder(observer); final WeatherType[] weatherTypes = WeatherType.values(); for (int i = 1; i < 20; i++) { weather.timePasses(); @@ -80,4 +97,4 @@ public class WeatherTest extends StdOutTest { verifyNoMoreInteractions(observer); } -} \ No newline at end of file +} diff --git a/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java b/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java index 758dbca8c..61d619a60 100644 --- a/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java +++ b/observer/src/test/java/com/iluwatar/observer/generic/GWeatherTest.java @@ -22,25 +22,35 @@ */ package com.iluwatar.observer.generic; -import com.iluwatar.observer.StdOutTest; import com.iluwatar.observer.WeatherObserver; import com.iluwatar.observer.WeatherType; - +import com.iluwatar.observer.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; /** * Date: 12/27/15 - 11:08 AM * * @author Jeroen Meulemeester */ -public class GWeatherTest extends StdOutTest { +public class GWeatherTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(GWeather.class); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Add a {@link WeatherObserver}, verify if it gets notified of a weather change, remove the @@ -55,14 +65,15 @@ public class GWeatherTest extends StdOutTest { verifyZeroInteractions(observer); weather.timePasses(); - verify(getStdOutMock()).println("The weather changed to rainy."); + assertEquals("The weather changed to rainy.", appender.getLastMessage()); verify(observer).update(weather, WeatherType.RAINY); weather.removeObserver(observer); weather.timePasses(); - verify(getStdOutMock()).println("The weather changed to windy."); + assertEquals("The weather changed to windy.", appender.getLastMessage()); - verifyNoMoreInteractions(observer, getStdOutMock()); + verifyNoMoreInteractions(observer); + assertEquals(2, appender.getLogSize()); } /** @@ -74,7 +85,7 @@ public class GWeatherTest extends StdOutTest { final GWeather weather = new GWeather(); weather.addObserver(observer); - final InOrder inOrder = inOrder(observer, getStdOutMock()); + final InOrder inOrder = inOrder(observer); final WeatherType[] weatherTypes = WeatherType.values(); for (int i = 1; i < 20; i++) { weather.timePasses(); @@ -84,4 +95,4 @@ public class GWeatherTest extends StdOutTest { verifyNoMoreInteractions(observer); } -} \ No newline at end of file +} diff --git a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java index 33d8daaf5..d01d30992 100644 --- a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java +++ b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java @@ -22,23 +22,34 @@ */ package com.iluwatar.observer.generic; -import com.iluwatar.observer.StdOutTest; import com.iluwatar.observer.WeatherType; - +import com.iluwatar.observer.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import java.util.function.Supplier; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/27/15 - 11:44 AM * * @author Jeroen Meulemeester */ -public abstract class ObserverTest extends StdOutTest { +public abstract class ObserverTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } /** * The observer instance factory @@ -74,11 +85,11 @@ public abstract class ObserverTest extends StdOutTest { @Test public void testObserver() { final O observer = this.factory.get(); - verifyZeroInteractions(getStdOutMock()); + assertEquals(0, appender.getLogSize()); observer.update(null, this.weather); - verify(getStdOutMock()).println(this.response); - verifyNoMoreInteractions(getStdOutMock()); + assertEquals(this.response, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java b/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java new file mode 100644 index 000000000..4e6e49768 --- /dev/null +++ b/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * Copyright (c) 2014 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.observer.utils; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; + +public class InMemoryAppender extends AppenderBase { + private 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 int getLogSize() { + return log.size(); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } +} diff --git a/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java b/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java index 01a5dfaa6..983287c3c 100644 --- a/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java +++ b/poison-pill/src/test/java/com/iluwatar/poison/pill/ConsumerTest.java @@ -22,19 +22,38 @@ */ package com.iluwatar.poison.pill; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; +import org.slf4j.LoggerFactory; import java.time.LocalDateTime; +import java.util.LinkedList; +import java.util.List; -import static org.mockito.Mockito.inOrder; +import static org.junit.Assert.assertTrue; /** * Date: 12/27/15 - 9:45 PM * * @author Jeroen Meulemeester */ -public class ConsumerTest extends StdOutTest { +public class ConsumerTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Consumer.class); + } + + @After + public void tearDown() { + appender.stop(); + } @Test public void testConsume() throws Exception { @@ -52,12 +71,9 @@ public class ConsumerTest extends StdOutTest { new Consumer("NSA", queue).consume(); - final InOrder inOrder = inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("Message [Hello!] from [you] received by [NSA]"); - inOrder.verify(getStdOutMock()).println("Message [Hi!] from [me] received by [NSA]"); - inOrder.verify(getStdOutMock()).println("Consumer NSA receive request to terminate."); - inOrder.verifyNoMoreInteractions(); - + assertTrue(appender.logContains("Message [Hello!] from [you] received by [NSA]")); + assertTrue(appender.logContains("Message [Hi!] from [me] received by [NSA]")); + assertTrue(appender.logContains("Consumer NSA receive request to terminate.")); } /** @@ -75,4 +91,22 @@ public class ConsumerTest extends StdOutTest { return msg; } -} \ No newline at end of file + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender(Class clazz) { + ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public boolean logContains(String message) { + return log.stream().anyMatch(event -> event.getFormattedMessage().equals(message)); + } + } + +} diff --git a/poison-pill/src/test/java/com/iluwatar/poison/pill/StdOutTest.java b/poison-pill/src/test/java/com/iluwatar/poison/pill/StdOutTest.java deleted file mode 100644 index f1b3c4840..000000000 --- a/poison-pill/src/test/java/com/iluwatar/poison/pill/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.poison.pill; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/private-class-data/src/test/java/com/iluwatar/privateclassdata/ImmutableStewTest.java b/private-class-data/src/test/java/com/iluwatar/privateclassdata/ImmutableStewTest.java index 58867d303..431375ef7 100644 --- a/private-class-data/src/test/java/com/iluwatar/privateclassdata/ImmutableStewTest.java +++ b/private-class-data/src/test/java/com/iluwatar/privateclassdata/ImmutableStewTest.java @@ -22,18 +22,31 @@ */ package com.iluwatar.privateclassdata; +import com.iluwatar.privateclassdata.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.verify; +import static org.junit.Assert.assertEquals; /** * Date: 12/27/15 - 10:46 PM * * @author Jeroen Meulemeester */ -public class ImmutableStewTest extends StdOutTest { +public class ImmutableStewTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Verify if mixing the stew doesn't change the internal state @@ -41,15 +54,14 @@ public class ImmutableStewTest extends StdOutTest { @Test public void testMix() { final Stew stew = new Stew(1, 2, 3, 4); - final String message = "Mixing the stew we find: 1 potatoes, 2 carrots, 3 meat and 4 peppers"; + final String expectedMessage = "Mixing the stew we find: 1 potatoes, 2 carrots, 3 meat and 4 peppers"; - final InOrder inOrder = inOrder(getStdOutMock()); for (int i = 0; i < 20; i++) { stew.mix(); - inOrder.verify(getStdOutMock()).println(message); + assertEquals(expectedMessage, appender.getLastMessage()); } - inOrder.verifyNoMoreInteractions(); + assertEquals(20, appender.getLogSize()); } /** @@ -60,15 +72,12 @@ public class ImmutableStewTest extends StdOutTest { final Stew stew = new Stew(1, 2, 3, 4); stew.mix(); - verify(getStdOutMock()) - .println("Mixing the stew we find: 1 potatoes, 2 carrots, 3 meat and 4 peppers"); + assertEquals("Mixing the stew we find: 1 potatoes, 2 carrots, 3 meat and 4 peppers", appender.getLastMessage()); stew.taste(); - verify(getStdOutMock()).println("Tasting the stew"); + assertEquals("Tasting the stew", appender.getLastMessage()); stew.mix(); - verify(getStdOutMock()) - .println("Mixing the stew we find: 0 potatoes, 1 carrots, 2 meat and 3 peppers"); - + assertEquals("Mixing the stew we find: 0 potatoes, 1 carrots, 2 meat and 3 peppers", appender.getLastMessage()); } -} \ No newline at end of file +} diff --git a/private-class-data/src/test/java/com/iluwatar/privateclassdata/StdOutTest.java b/private-class-data/src/test/java/com/iluwatar/privateclassdata/StdOutTest.java deleted file mode 100644 index f90551020..000000000 --- a/private-class-data/src/test/java/com/iluwatar/privateclassdata/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.privateclassdata; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/private-class-data/src/test/java/com/iluwatar/privateclassdata/StewTest.java b/private-class-data/src/test/java/com/iluwatar/privateclassdata/StewTest.java index a894e4ae0..f2e3c5fad 100644 --- a/private-class-data/src/test/java/com/iluwatar/privateclassdata/StewTest.java +++ b/private-class-data/src/test/java/com/iluwatar/privateclassdata/StewTest.java @@ -22,17 +22,31 @@ */ package com.iluwatar.privateclassdata; +import com.iluwatar.privateclassdata.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; -import static org.mockito.Mockito.inOrder; +import static org.junit.Assert.assertEquals; /** * Date: 12/27/15 - 10:46 PM * * @author Jeroen Meulemeester */ -public class StewTest extends StdOutTest { +public class StewTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } /** * Verify if mixing the stew doesn't change the internal state @@ -43,13 +57,12 @@ public class StewTest extends StdOutTest { final String expectedMessage = "Mixing the immutable stew we find: 1 potatoes, " + "2 carrots, 3 meat and 4 peppers"; - final InOrder inOrder = inOrder(getStdOutMock()); for (int i = 0; i < 20; i++) { stew.mix(); - inOrder.verify(getStdOutMock()).println(expectedMessage); + assertEquals(expectedMessage, appender.getLastMessage()); } - inOrder.verifyNoMoreInteractions(); + assertEquals(20, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java b/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java new file mode 100644 index 000000000..4b2def101 --- /dev/null +++ b/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright (c) 2014 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.privateclassdata.utils; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; + +public class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } +} diff --git a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ConsumerTest.java b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ConsumerTest.java index 2ca547a0b..dd725df75 100644 --- a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ConsumerTest.java +++ b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ConsumerTest.java @@ -23,18 +23,15 @@ package com.iluwatar.producer.consumer; import org.junit.Test; -import org.mockito.InOrder; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.*; /** * Date: 12/27/15 - 11:01 PM * * @author Jeroen Meulemeester */ -public class ConsumerTest extends StdOutTest { +public class ConsumerTest { private static final int ITEM_COUNT = 5; @@ -48,14 +45,11 @@ public class ConsumerTest extends StdOutTest { reset(queue); // Don't count the preparation above as interactions with the queue final Consumer consumer = new Consumer("consumer", queue); - final InOrder inOrder = inOrder(getStdOutMock()); for (int id = 0; id < ITEM_COUNT; id++) { consumer.consume(); - inOrder.verify(getStdOutMock()) - .println("Consumer [consumer] consume item [" + id + "] produced by [producer]"); } - inOrder.verifyNoMoreInteractions(); + verify(queue, times(ITEM_COUNT)).take(); } } diff --git a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/StdOutTest.java b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/StdOutTest.java deleted file mode 100644 index 1e1c41f75..000000000 --- a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.producer.consumer; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/proxy/src/test/java/com/iluwatar/proxy/StdOutTest.java b/proxy/src/test/java/com/iluwatar/proxy/StdOutTest.java deleted file mode 100644 index 48831444a..000000000 --- a/proxy/src/test/java/com/iluwatar/proxy/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.proxy; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/proxy/src/test/java/com/iluwatar/proxy/WizardTowerProxyTest.java b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerProxyTest.java index b87b7a0bc..921624f63 100644 --- a/proxy/src/test/java/com/iluwatar/proxy/WizardTowerProxyTest.java +++ b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerProxyTest.java @@ -22,17 +22,32 @@ */ package com.iluwatar.proxy; +import com.iluwatar.proxy.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; -import static org.mockito.Mockito.inOrder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Date: 12/28/15 - 9:18 PM * * @author Jeroen Meulemeester */ -public class WizardTowerProxyTest extends StdOutTest { +public class WizardTowerProxyTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } @Test public void testEnter() throws Exception { @@ -48,13 +63,11 @@ public class WizardTowerProxyTest extends StdOutTest { tower.enter(wizard); } - final InOrder inOrder = inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("Gandalf enters the tower."); - inOrder.verify(getStdOutMock()).println("Dumbledore enters the tower."); - inOrder.verify(getStdOutMock()).println("Oz enters the tower."); - inOrder.verify(getStdOutMock()).println("Merlin is not allowed to enter!"); - inOrder.verifyNoMoreInteractions(); - + assertTrue(appender.logContains("Gandalf enters the tower.")); + assertTrue(appender.logContains("Dumbledore enters the tower.")); + assertTrue(appender.logContains("Oz enters the tower.")); + assertTrue(appender.logContains("Merlin is not allowed to enter!")); + assertEquals(4, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/proxy/src/test/java/com/iluwatar/proxy/WizardTowerTest.java b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerTest.java index 9996434f5..ab56115ca 100644 --- a/proxy/src/test/java/com/iluwatar/proxy/WizardTowerTest.java +++ b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerTest.java @@ -22,17 +22,32 @@ */ package com.iluwatar.proxy; +import com.iluwatar.proxy.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; -import static org.mockito.Mockito.inOrder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Date: 12/28/15 - 9:18 PM * * @author Jeroen Meulemeester */ -public class WizardTowerTest extends StdOutTest { +public class WizardTowerTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(WizardTower.class); + } + + @After + public void tearDown() { + appender.stop(); + } @Test public void testEnter() throws Exception { @@ -48,13 +63,11 @@ public class WizardTowerTest extends StdOutTest { tower.enter(wizard); } - final InOrder inOrder = inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("Gandalf enters the tower."); - inOrder.verify(getStdOutMock()).println("Dumbledore enters the tower."); - inOrder.verify(getStdOutMock()).println("Oz enters the tower."); - inOrder.verify(getStdOutMock()).println("Merlin enters the tower."); - inOrder.verifyNoMoreInteractions(); - + assertTrue(appender.logContains("Gandalf enters the tower.")); + assertTrue(appender.logContains("Dumbledore enters the tower.")); + assertTrue(appender.logContains("Oz enters the tower.")); + assertTrue(appender.logContains("Merlin enters the tower.")); + assertEquals(4, appender.getLogSize()); } -} \ No newline at end of file +} diff --git a/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java b/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java new file mode 100644 index 000000000..857d3e548 --- /dev/null +++ b/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * Copyright (c) 2014 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.proxy.utils; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; + +public class InMemoryAppender extends AppenderBase { + private 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().equals(message)); + } + + public int getLogSize() { + return log.size(); + } +} 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 index dc8feb04f..7d0ac70bf 100644 --- 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 @@ -23,21 +23,35 @@ package com.iluwatar.reader.writer.lock; -import static org.mockito.Mockito.inOrder; +import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import org.junit.Test; -import org.mockito.InOrder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertTrue; /** * @author hongshuwei@gmail.com */ -public class ReaderAndWriterTest extends StdOutTest { +public class ReaderAndWriterTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } private static final Logger LOGGER = LoggerFactory.getLogger(ReaderAndWriterTest.class); @@ -65,11 +79,10 @@ public class ReaderAndWriterTest extends StdOutTest { LOGGER.error("Error waiting for ExecutorService shutdown", e); } - final InOrder inOrder = inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("Reader 1 begin"); - inOrder.verify(getStdOutMock()).println("Reader 1 finish"); - inOrder.verify(getStdOutMock()).println("Writer 1 begin"); - inOrder.verify(getStdOutMock()).println("Writer 1 finish"); + assertTrue(appender.logContains("Reader 1 begin")); + assertTrue(appender.logContains("Reader 1 finish")); + assertTrue(appender.logContains("Writer 1 begin")); + assertTrue(appender.logContains("Writer 1 finish")); } /** @@ -96,11 +109,10 @@ public class ReaderAndWriterTest extends StdOutTest { LOGGER.error("Error waiting for ExecutorService shutdown", e); } - final InOrder inOrder = inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("Writer 1 begin"); - inOrder.verify(getStdOutMock()).println("Writer 1 finish"); - inOrder.verify(getStdOutMock()).println("Reader 1 begin"); - inOrder.verify(getStdOutMock()).println("Reader 1 finish"); + 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 index a51120bf8..9830eda67 100644 --- 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 @@ -22,22 +22,36 @@ */ package com.iluwatar.reader.writer.lock; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.spy; +import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import org.junit.Test; -import org.mockito.InOrder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static junit.framework.TestCase.assertTrue; +import static org.mockito.Mockito.spy; /** * @author hongshuwei@gmail.com */ -public class ReaderTest extends StdOutTest { +public class ReaderTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Reader.class); + } + + @After + public void tearDown() { + appender.stop(); + } private static final Logger LOGGER = LoggerFactory.getLogger(ReaderTest.class); @@ -66,11 +80,9 @@ public class ReaderTest extends StdOutTest { // Read operation will hold the read lock 250 milliseconds, so here we prove that multiple reads // can be performed in the same time. - final InOrder inOrder = inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("Reader 1 begin"); - inOrder.verify(getStdOutMock()).println("Reader 2 begin"); - inOrder.verify(getStdOutMock()).println("Reader 1 finish"); - inOrder.verify(getStdOutMock()).println("Reader 2 finish"); - + 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/StdOutTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/StdOutTest.java deleted file mode 100644 index 7a1af09c0..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/StdOutTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} 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 index 729b5eff3..4bf6d0747 100644 --- 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 @@ -22,22 +22,36 @@ */ package com.iluwatar.reader.writer.lock; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.spy; +import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import org.junit.Test; -import org.mockito.InOrder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.spy; /** * @author hongshuwei@gmail.com */ -public class WriterTest extends StdOutTest { +public class WriterTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Writer.class); + } + + @After + public void tearDown() { + appender.stop(); + } private static final Logger LOGGER = LoggerFactory.getLogger(WriterTest.class); @@ -67,10 +81,9 @@ public class WriterTest extends StdOutTest { // 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. - final InOrder inOrder = inOrder(getStdOutMock()); - inOrder.verify(getStdOutMock()).println("Writer 1 begin"); - inOrder.verify(getStdOutMock()).println("Writer 1 finish"); - inOrder.verify(getStdOutMock()).println("Writer 2 begin"); - inOrder.verify(getStdOutMock()).println("Writer 2 finish"); + 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 new file mode 100644 index 000000000..44fcb084b --- /dev/null +++ b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright (c) 2014 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 org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; + +public class InMemoryAppender extends AppenderBase { + private 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().equals(message)); + } +} diff --git a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java index 55bdaf19c..638b06ecc 100644 --- a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java +++ b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java @@ -22,28 +22,64 @@ */ package com.iluwatar.resource.acquisition.is.initialization; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; +import org.slf4j.LoggerFactory; -import static org.mockito.Mockito.inOrder; +import java.util.LinkedList; +import java.util.List; + +import static org.junit.Assert.assertTrue; /** * Date: 12/28/15 - 9:31 PM * * @author Jeroen Meulemeester */ -public class ClosableTest extends StdOutTest { +public class ClosableTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } @Test public void testOpenClose() throws Exception { - final InOrder inOrder = inOrder(getStdOutMock()); try (final SlidingDoor door = new SlidingDoor(); final TreasureChest chest = new TreasureChest()) { - inOrder.verify(getStdOutMock()).println("Sliding door opens."); - inOrder.verify(getStdOutMock()).println("Treasure chest opens."); + assertTrue(appender.logContains("Sliding door opens.")); + assertTrue(appender.logContains("Treasure chest opens.")); } - inOrder.verify(getStdOutMock()).println("Treasure chest closes."); - inOrder.verify(getStdOutMock()).println("Sliding door closes."); - inOrder.verifyNoMoreInteractions(); + assertTrue(appender.logContains("Treasure chest closes.")); + assertTrue(appender.logContains("Sliding door closes.")); } -} \ No newline at end of file + public class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + 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.getMessage().equals(message)); + } + } + +} diff --git a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/StdOutTest.java b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/StdOutTest.java deleted file mode 100644 index 42cb42e6b..000000000 --- a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.resource.acquisition.is.initialization; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/state/src/test/java/com/iluwatar/state/MammothTest.java b/state/src/test/java/com/iluwatar/state/MammothTest.java index 4fe37bfd1..be4c0d892 100644 --- a/state/src/test/java/com/iluwatar/state/MammothTest.java +++ b/state/src/test/java/com/iluwatar/state/MammothTest.java @@ -22,17 +22,19 @@ */ package com.iluwatar.state; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; +import java.util.LinkedList; +import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; /** * Date: 12/29/15 - 8:27 PM @@ -41,31 +43,16 @@ import static org.mockito.Mockito.mock; */ public class MammothTest { - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); + private InMemoryAppender appender; - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ @Before public void setUp() { - System.setOut(this.stdOutMock); + appender = new InMemoryAppender(); } - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ @After public void tearDown() { - System.setOut(this.stdOutOrig); + appender.stop(); } /** @@ -74,28 +61,27 @@ public class MammothTest { */ @Test public void testTimePasses() { - final InOrder inOrder = Mockito.inOrder(this.stdOutMock); final Mammoth mammoth = new Mammoth(); mammoth.observe(); - inOrder.verify(this.stdOutMock).println("The mammoth is calm and peaceful."); - inOrder.verifyNoMoreInteractions(); + assertEquals("The mammoth is calm and peaceful.", appender.getLastMessage()); + assertEquals(1 , appender.getLogSize()); mammoth.timePasses(); - inOrder.verify(this.stdOutMock).println("The mammoth gets angry!"); - inOrder.verifyNoMoreInteractions(); + assertEquals("The mammoth gets angry!", appender.getLastMessage()); + assertEquals(2 , appender.getLogSize()); mammoth.observe(); - inOrder.verify(this.stdOutMock).println("The mammoth is furious!"); - inOrder.verifyNoMoreInteractions(); + assertEquals("The mammoth is furious!", appender.getLastMessage()); + assertEquals(3 , appender.getLogSize()); mammoth.timePasses(); - inOrder.verify(this.stdOutMock).println("The mammoth calms down."); - inOrder.verifyNoMoreInteractions(); + assertEquals("The mammoth calms down.", appender.getLastMessage()); + assertEquals(4 , appender.getLogSize()); mammoth.observe(); - inOrder.verify(this.stdOutMock).println("The mammoth is calm and peaceful."); - inOrder.verifyNoMoreInteractions(); + assertEquals("The mammoth is calm and peaceful.", appender.getLastMessage()); + assertEquals(5 , appender.getLogSize()); } @@ -109,4 +95,26 @@ public class MammothTest { assertEquals("The mammoth", toString); } -} \ No newline at end of file + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + } + +} diff --git a/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java index 35f4c1a82..d04e0f5c1 100644 --- a/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java +++ b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java @@ -22,19 +22,22 @@ */ package com.iluwatar.strategy; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; import java.util.Arrays; import java.util.Collection; +import java.util.LinkedList; +import java.util.List; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/29/15 - 10:58 PM @@ -71,20 +74,22 @@ public class DragonSlayingStrategyTest { private final DragonSlayingStrategy strategy; /** - * The expected action on the std-out + * The expected action in the log */ private final String expectedResult; - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; /** * Create a new test instance for the given strategy @@ -97,30 +102,35 @@ public class DragonSlayingStrategyTest { this.expectedResult = expectedResult; } - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - /** * Test if executing the strategy gives the correct response */ @Test public void testExecute() { this.strategy.execute(); - verify(this.stdOutMock).println(this.expectedResult); - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(this.expectedResult, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } -} \ No newline at end of file + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + } +} diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java index e0cb90d42..0ea337f93 100644 --- a/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java +++ b/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java @@ -22,19 +22,19 @@ */ package com.iluwatar.templatemethod; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; +import org.slf4j.LoggerFactory; -import java.io.PrintStream; +import java.util.LinkedList; +import java.util.List; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.junit.Assert.assertTrue; /** * Date: 12/30/15 - 18:12 PM @@ -43,6 +43,18 @@ import static org.mockito.Mockito.verifyZeroInteractions; */ public abstract class StealingMethodTest { + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } + /** * The tested stealing method */ @@ -68,17 +80,6 @@ public abstract class StealingMethodTest { */ private final String expectedStealMethod; - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - /** * Create a new test for the given stealing method, together with the expected results * @@ -98,22 +99,6 @@ public abstract class StealingMethodTest { this.expectedStealMethod = expectedStealMethod; } - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - /** * Verify if the thief picks the correct target */ @@ -127,11 +112,11 @@ public abstract class StealingMethodTest { */ @Test public void testConfuseTarget() { - verifyZeroInteractions(this.stdOutMock); + assertEquals(0, appender.getLogSize()); this.method.confuseTarget(this.expectedTarget); - verify(this.stdOutMock).println(this.expectedConfuseMethod); - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(this.expectedConfuseMethod, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } /** @@ -139,11 +124,11 @@ public abstract class StealingMethodTest { */ @Test public void testStealTheItem() { - verifyZeroInteractions(this.stdOutMock); + assertEquals(0, appender.getLogSize()); this.method.stealTheItem(this.expectedTarget); - verify(this.stdOutMock).println(this.expectedStealMethod); - verifyNoMoreInteractions(this.stdOutMock); + assertEquals(this.expectedStealMethod, appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } /** @@ -151,14 +136,37 @@ public abstract class StealingMethodTest { */ @Test public void testSteal() { - final InOrder inOrder = inOrder(this.stdOutMock); - this.method.steal(); - inOrder.verify(this.stdOutMock).println(this.expectedTargetResult); - inOrder.verify(this.stdOutMock).println(this.expectedConfuseMethod); - inOrder.verify(this.stdOutMock).println(this.expectedStealMethod); - inOrder.verifyNoMoreInteractions(); + assertTrue(appender.logContains(this.expectedTargetResult)); + assertTrue(appender.logContains(this.expectedConfuseMethod)); + assertTrue(appender.logContains(this.expectedStealMethod)); + assertEquals(3, appender.getLogSize()); } -} \ No newline at end of file + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + + public boolean logContains(String message) { + return log.stream().anyMatch(event -> event.getFormattedMessage().equals(message)); + } + } +} diff --git a/twin/src/test/java/com/iluwatar/twin/BallItemTest.java b/twin/src/test/java/com/iluwatar/twin/BallItemTest.java index 4bb9a2111..439a64da1 100644 --- a/twin/src/test/java/com/iluwatar/twin/BallItemTest.java +++ b/twin/src/test/java/com/iluwatar/twin/BallItemTest.java @@ -22,20 +22,40 @@ */ package com.iluwatar.twin; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; +import org.slf4j.LoggerFactory; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import java.util.LinkedList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.*; /** * Date: 12/30/15 - 18:44 PM * * @author Jeroen Meulemeester */ -public class BallItemTest extends StdOutTest { +public class BallItemTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } @Test public void testClick() { @@ -63,10 +83,11 @@ public class BallItemTest extends StdOutTest { ballItem.setTwin(ballThread); ballItem.draw(); - verify(getStdOutMock()).println("draw"); - verify(getStdOutMock()).println("doDraw"); + assertTrue(appender.logContains("draw")); + assertTrue(appender.logContains("doDraw")); - verifyNoMoreInteractions(ballThread, getStdOutMock()); + verifyNoMoreInteractions(ballThread); + assertEquals(2, appender.getLogSize()); } @Test @@ -76,9 +97,32 @@ public class BallItemTest extends StdOutTest { ballItem.setTwin(ballThread); ballItem.move(); - verify(getStdOutMock()).println("move"); + assertTrue(appender.logContains("move")); - verifyNoMoreInteractions(ballThread, getStdOutMock()); + verifyNoMoreInteractions(ballThread); + assertEquals(1, appender.getLogSize()); } -} \ No newline at end of file + public class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + 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.getMessage().equals(message)); + } + + public int getLogSize() { + return log.size(); + } + } + +} diff --git a/twin/src/test/java/com/iluwatar/twin/StdOutTest.java b/twin/src/test/java/com/iluwatar/twin/StdOutTest.java deleted file mode 100644 index b3baf8abd..000000000 --- a/twin/src/test/java/com/iluwatar/twin/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.twin; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java b/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java deleted file mode 100644 index 075f235f5..000000000 --- a/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.visitor; - -import org.junit.After; -import org.junit.Before; - -import java.io.PrintStream; - -import static org.mockito.Mockito.mock; - -/** - * Date: 12/10/15 - 8:37 PM - * - * @author Jeroen Meulemeester - */ -public abstract class StdOutTest { - - /** - * The mocked standard out {@link PrintStream}, required since some actions don't have any - * influence on accessible objects, except for writing to std-out using {@link System#out} - */ - private final PrintStream stdOutMock = mock(PrintStream.class); - - /** - * Keep the original std-out so it can be restored after the test - */ - private final PrintStream stdOutOrig = System.out; - - /** - * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test - */ - @Before - public void setUp() { - System.setOut(this.stdOutMock); - } - - /** - * Removed the mocked std-out {@link PrintStream} again from the {@link System} class - */ - @After - public void tearDown() { - System.setOut(this.stdOutOrig); - } - - /** - * Get the mocked stdOut {@link PrintStream} - * - * @return The stdOut print stream mock, renewed before each test - */ - final PrintStream getStdOutMock() { - return this.stdOutMock; - } - -} diff --git a/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java index 4a131bbf2..a0c8b4eea 100644 --- a/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java +++ b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java @@ -22,19 +22,38 @@ */ package com.iluwatar.visitor; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.slf4j.LoggerFactory; +import java.util.LinkedList; +import java.util.List; import java.util.Optional; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.junit.Assert.assertEquals; /** * Date: 12/30/15 - 18:59 PM * * @author Jeroen Meulemeester */ -public abstract class VisitorTest extends StdOutTest { +public abstract class VisitorTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(); + } + + @After + public void tearDown() { + appender.stop(); + } /** * The tested visitor instance @@ -76,27 +95,48 @@ public abstract class VisitorTest extends StdOutTest { public void testVisitCommander() { this.visitor.visitCommander(new Commander()); if (this.commanderResponse.isPresent()) { - verify(getStdOutMock()).println(this.commanderResponse.get()); + assertEquals(this.commanderResponse.get(), appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } - verifyNoMoreInteractions(getStdOutMock()); } @Test public void testVisitSergeant() { this.visitor.visitSergeant(new Sergeant()); if (this.sergeantResponse.isPresent()) { - verify(getStdOutMock()).println(this.sergeantResponse.get()); + assertEquals(this.sergeantResponse.get(), appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } - verifyNoMoreInteractions(getStdOutMock()); } @Test public void testVisitSoldier() { this.visitor.visitSoldier(new Soldier()); if (this.soldierResponse.isPresent()) { - verify(getStdOutMock()).println(this.soldierResponse.get()); + assertEquals(this.soldierResponse.get(), appender.getLastMessage()); + assertEquals(1, appender.getLogSize()); } - verifyNoMoreInteractions(getStdOutMock()); } + private class InMemoryAppender extends AppenderBase { + private List log = new LinkedList<>(); + + public InMemoryAppender() { + ((Logger) LoggerFactory.getLogger("root")).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + log.add(eventObject); + } + + public int getLogSize() { + return log.size(); + } + + public String getLastMessage() { + return log.get(log.size() - 1).getFormattedMessage(); + } + } } From b37190a2140555d981161bc0e4ad210452cecde4 Mon Sep 17 00:00:00 2001 From: daniel-bryla Date: Fri, 4 Nov 2016 12:19:32 +0100 Subject: [PATCH 105/492] #502 Introduced logging in new example --- .../main/java/com/iluwatar/caching/App.java | 10 +-- .../com/iluwatar/event/asynchronous/App.java | 61 ++++++++++--------- .../iluwatar/event/asynchronous/Event.java | 13 ++-- .../event/asynchronous/EventManager.java | 12 ++-- .../asynchronous/EventAsynchronousTest.java | 18 +++--- 5 files changed, 64 insertions(+), 50 deletions(-) diff --git a/caching/src/main/java/com/iluwatar/caching/App.java b/caching/src/main/java/com/iluwatar/caching/App.java index 8a4ff0b8d..f30b20e05 100644 --- a/caching/src/main/java/com/iluwatar/caching/App.java +++ b/caching/src/main/java/com/iluwatar/caching/App.java @@ -149,9 +149,9 @@ public class App { * Cache-Aside */ public void useCacheAsideStategy() { - System.out.println("# CachingPolicy.ASIDE"); + LOGGER.info("# CachingPolicy.ASIDE"); AppManager.initCachingPolicy(CachingPolicy.ASIDE); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); UserAccount userAccount3 = new UserAccount("003", "Adam", "He likes food."); UserAccount userAccount4 = new UserAccount("004", "Rita", "She hates cats."); @@ -160,10 +160,10 @@ public class App { AppManager.save(userAccount4); AppManager.save(userAccount5); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("003"); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); AppManager.find("004"); - System.out.println(AppManager.printCacheContent()); + LOGGER.info(AppManager.printCacheContent()); } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java index 5a2565940..c7c543434 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/App.java @@ -16,38 +16,43 @@ */ package com.iluwatar.event.asynchronous; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.Scanner; /** - * + * * This application demonstrates the Event-based Asynchronous pattern. Essentially, users (of the pattern) may * choose to run events in an Asynchronous or Synchronous mode. There can be multiple Asynchronous events running at * once but only one Synchronous event can run at a time. Asynchronous events are synonymous to multi-threads. The key * point here is that the threads run in the background and the user is free to carry on with other processes. Once an * event is complete, the appropriate listener/callback method will be called. The listener then proceeds to carry out * further processing depending on the needs of the user. - * + * * The {@link EventManager} manages the events/threads that the user creates. Currently, the supported event operations * are: start, stop, getStatus. For Synchronous events, the user is unable to * start another (Synchronous) event if one is already running at the time. The running event would have to either be * stopped or completed before a new event can be started. - * + * * The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many * of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:- * (1) Perform time-consuming tasks, such as downloads and database operations, "in the background," without * interrupting your application. (2) Execute multiple operations simultaneously, receiving notifications when each * completes. (3) Wait for resources to become available without stopping ("hanging") your application. (4) Communicate * with pending asynchronous operations using the familiar events-and-delegates model. - * + * * @see EventManager * @see Event * */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + public static final String PROP_FILE_NAME = "config.properties"; boolean interactiveMode = false; @@ -77,7 +82,7 @@ public class App { try { prop.load(inputStream); } catch (IOException e) { - System.out.println(PROP_FILE_NAME + " was not found. Defaulting to non-interactive mode."); + LOGGER.error("{} was not found. Defaulting to non-interactive mode.", PROP_FILE_NAME, e); } String property = prop.getProperty("INTERACTIVE_MODE"); if (property.equalsIgnoreCase("YES")) { @@ -106,27 +111,27 @@ public class App { try { // Create an Asynchronous event. int aEventId = eventManager.createAsync(60); - System.out.println("Async Event [" + aEventId + "] has been created."); + LOGGER.info("Async Event [{}] has been created.", aEventId); eventManager.start(aEventId); - System.out.println("Async Event [" + aEventId + "] has been started."); + LOGGER.info("Async Event [{}] has been started.", aEventId); // Create a Synchronous event. int sEventId = eventManager.create(60); - System.out.println("Sync Event [" + sEventId + "] has been created."); + LOGGER.info("Sync Event [{}] has been created.", sEventId); eventManager.start(sEventId); - System.out.println("Sync Event [" + sEventId + "] has been started."); + LOGGER.info("Sync Event [{}] has been started.", sEventId); eventManager.status(aEventId); eventManager.status(sEventId); eventManager.cancel(aEventId); - System.out.println("Async Event [" + aEventId + "] has been stopped."); + LOGGER.info("Async Event [{}] has been stopped.", aEventId); eventManager.cancel(sEventId); - System.out.println("Sync Event [" + sEventId + "] has been stopped."); + LOGGER.info("Sync Event [{}] has been stopped.", sEventId); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } @@ -139,58 +144,58 @@ public class App { Scanner s = new Scanner(System.in); int option = -1; while (option != 4) { - System.out.println("Hello. Would you like to boil some eggs?"); - System.out.println("(1) BOIL AN EGG \n(2) STOP BOILING THIS EGG \n(3) HOW ARE MY EGGS? \n(4) EXIT"); - System.out.print("Choose [1,2,3,4]: "); + LOGGER.info("Hello. Would you like to boil some eggs?"); + LOGGER.info("(1) BOIL AN EGG \n(2) STOP BOILING THIS EGG \n(3) HOW ARE MY EGGS? \n(4) EXIT"); + LOGGER.info("Choose [1,2,3,4]: "); option = s.nextInt(); if (option == 1) { s.nextLine(); - System.out.print("Boil multiple eggs at once (A) or boil them one-by-one (S)?: "); + LOGGER.info("Boil multiple eggs at once (A) or boil them one-by-one (S)?: "); String eventType = s.nextLine(); - System.out.print("How long should this egg be boiled for (in seconds)?: "); + LOGGER.info("How long should this egg be boiled for (in seconds)?: "); int eventTime = s.nextInt(); if (eventType.equalsIgnoreCase("A")) { try { int eventId = eventManager.createAsync(eventTime); eventManager.start(eventId); - System.out.println("Egg [" + eventId + "] is being boiled."); + LOGGER.info("Egg [{}] is being boiled.", eventId); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } else if (eventType.equalsIgnoreCase("S")) { try { int eventId = eventManager.create(eventTime); eventManager.start(eventId); - System.out.println("Egg [" + eventId + "] is being boiled."); + LOGGER.info("Egg [{}] is being boiled.", eventId); } catch (MaxNumOfEventsAllowedException | InvalidOperationException | LongRunningEventException | EventDoesNotExistException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } else { - System.out.println("Unknown event type."); + LOGGER.info("Unknown event type."); } } else if (option == 2) { - System.out.print("Which egg?: "); + LOGGER.info("Which egg?: "); int eventId = s.nextInt(); try { eventManager.cancel(eventId); - System.out.println("Egg [" + eventId + "] is removed from boiler."); + LOGGER.info("Egg [{}] is removed from boiler.", eventId); } catch (EventDoesNotExistException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } else if (option == 3) { s.nextLine(); - System.out.print("Just one egg (O) OR all of them (A) ?: "); + LOGGER.info("Just one egg (O) OR all of them (A) ?: "); String eggChoice = s.nextLine(); if (eggChoice.equalsIgnoreCase("O")) { - System.out.print("Which egg?: "); + LOGGER.info("Which egg?: "); int eventId = s.nextInt(); try { eventManager.status(eventId); } catch (EventDoesNotExistException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } else if (eggChoice.equalsIgnoreCase("A")) { eventManager.statusOfAllEvents(); diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java index 5e557fff2..bd4687dd5 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/Event.java @@ -16,13 +16,18 @@ */ package com.iluwatar.event.asynchronous; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * + * * Each Event runs as a separate/individual thread. * */ public class Event implements IEvent, Runnable { + private static final Logger LOGGER = LoggerFactory.getLogger(Event.class); + private int eventId; private int eventTime; private boolean isSynchronous; @@ -31,7 +36,7 @@ public class Event implements IEvent, Runnable { private ThreadCompleteListener eventListener; /** - * + * * @param eventId event ID * @param eventTime event time * @param isSynchronous is of synchronous type @@ -63,9 +68,9 @@ public class Event implements IEvent, Runnable { @Override public void status() { if (!isComplete) { - System.out.println("[" + eventId + "] is not done."); + LOGGER.info("[{}] is not done.", eventId); } else { - System.out.println("[" + eventId + "] is done."); + LOGGER.info("[{}] is done.", eventId); } } diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java index dae995e38..e181e8704 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventManager.java @@ -22,7 +22,7 @@ import java.util.Random; import java.util.concurrent.ConcurrentHashMap; /** - * + * * EventManager handles and maintains a pool of event threads. {@link Event} threads are created upon user request. Thre * are two types of events; Asynchronous and Synchronous. There can be multiple Asynchronous events running at once but * only one Synchronous event running at a time. Currently supported event operations are: start, stop, and getStatus. @@ -52,7 +52,7 @@ public class EventManager implements ThreadCompleteListener { /** * Create a Synchronous event. - * + * * @param eventTime Time an event should run for. * @return eventId * @throws MaxNumOfEventsAllowedException When too many events are running at a time. @@ -74,7 +74,7 @@ public class EventManager implements ThreadCompleteListener { /** * Create an Asynchronous event. - * + * * @param eventTime Time an event should run for. * @return eventId * @throws MaxNumOfEventsAllowedException When too many events are running at a time. @@ -106,7 +106,7 @@ public class EventManager implements ThreadCompleteListener { /** * Starts event. - * + * * @param eventId The event that needs to be started. * @throws EventDoesNotExistException If event does not exist in our eventPool. */ @@ -120,7 +120,7 @@ public class EventManager implements ThreadCompleteListener { /** * Stops event. - * + * * @param eventId The event that needs to be stopped. * @throws EventDoesNotExistException If event does not exist in our eventPool. */ @@ -139,7 +139,7 @@ public class EventManager implements ThreadCompleteListener { /** * Get status of a running event. - * + * * @param eventId The event to inquire status of. * @throws EventDoesNotExistException If event does not exist in our eventPool. */ diff --git a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java index 213439203..f032c8971 100644 --- a/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java +++ b/event-asynchronous/src/test/java/com/iluwatar/event/asynchronous/EventAsynchronousTest.java @@ -16,10 +16,12 @@ */ package com.iluwatar.event.asynchronous; -import static org.junit.Assert.assertTrue; - import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertTrue; /** * @@ -29,6 +31,8 @@ import org.junit.Test; public class EventAsynchronousTest { App app; + private static final Logger LOGGER = LoggerFactory.getLogger(EventAsynchronousTest.class); + @Before public void setUp() { app = new App(); @@ -46,7 +50,7 @@ public class EventAsynchronousTest { eventManager.cancel(aEventId); assertTrue(eventManager.getEventPool().size() == 0); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } @@ -63,7 +67,7 @@ public class EventAsynchronousTest { assertTrue(eventManager.getEventPool().size() == 0); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } @@ -76,7 +80,7 @@ public class EventAsynchronousTest { sEventId = eventManager.create(60); eventManager.start(sEventId); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } @@ -101,7 +105,7 @@ public class EventAsynchronousTest { } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException | InvalidOperationException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } @@ -129,7 +133,7 @@ public class EventAsynchronousTest { assertTrue(eventManager.getEventPool().size() == 0); } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { - System.out.println(e.getMessage()); + LOGGER.error(e.getMessage()); } } } From 6f3e2985a4b19781d843c38c74772aa4d35641de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 6 Nov 2016 12:14:39 +0200 Subject: [PATCH 106/492] Create presentation template --- presentation.html | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 presentation.html diff --git a/presentation.html b/presentation.html new file mode 100644 index 000000000..b19c85a81 --- /dev/null +++ b/presentation.html @@ -0,0 +1,45 @@ + + + + Title + + + + + + + + + From e1ae1067dbf88b365c52d2b4a45ca221136bddfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 6 Nov 2016 12:26:03 +0200 Subject: [PATCH 107/492] Link Hexagonal Architecture pattern to corresponding blog entry --- hexagonal/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hexagonal/README.md b/hexagonal/README.md index 33c2ba9cb..27d31520c 100644 --- a/hexagonal/README.md +++ b/hexagonal/README.md @@ -26,6 +26,9 @@ Use Hexagonal Architecture pattern when * it is important that the application is fully testable * you use Domain Driven Design methodology and/or Microservices architectural style +## Tutorials +* [Build Maintainable Systems With Hexagonal Architecture](http://java-design-patterns.com/blog/build-maintainable-systems-with-hexagonal-architecture/) + ## Real world examples * [Apache Isis](https://isis.apache.org/) From 4c24d99414e55fa8cf8fe3c068317f323350f762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 12 Nov 2016 22:44:08 +0200 Subject: [PATCH 108/492] Work on Hexagonal Architecture presentation --- hexagonal/README.md | 4 +- hexagonal/etc/hexagon.png | Bin 0 -> 51788 bytes hexagonal/etc/layers.png | Bin 0 -> 15887 bytes hexagonal/etc/presentation.html | 95 ++++++++++++++++++++++++++++++++ presentation.html | 45 --------------- 5 files changed, 97 insertions(+), 47 deletions(-) create mode 100644 hexagonal/etc/hexagon.png create mode 100644 hexagonal/etc/layers.png create mode 100644 hexagonal/etc/presentation.html delete mode 100644 presentation.html diff --git a/hexagonal/README.md b/hexagonal/README.md index 33c2ba9cb..30f70f54c 100644 --- a/hexagonal/README.md +++ b/hexagonal/README.md @@ -23,8 +23,8 @@ Allow an application to equally be driven by users, programs, automated test or ## Applicability Use Hexagonal Architecture pattern when -* it is important that the application is fully testable -* you use Domain Driven Design methodology and/or Microservices architectural style +* When the application needs to be independent of any frameworks +* When it is important that the application highly maintainable and fully testable ## Real world examples diff --git a/hexagonal/etc/hexagon.png b/hexagonal/etc/hexagon.png new file mode 100644 index 0000000000000000000000000000000000000000..e2d14e91dd692d888f85998087c881c559191900 GIT binary patch literal 51788 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 literal 0 HcmV?d00001 diff --git a/hexagonal/etc/layers.png b/hexagonal/etc/layers.png new file mode 100644 index 0000000000000000000000000000000000000000..cb5a9c90bbe953ff87197bfb1834c34fac450f3c GIT binary patch literal 15887 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 Kh}Vc32LC_vUU`lH literal 0 HcmV?d00001 diff --git a/hexagonal/etc/presentation.html b/hexagonal/etc/presentation.html new file mode 100644 index 000000000..46e26c550 --- /dev/null +++ b/hexagonal/etc/presentation.html @@ -0,0 +1,95 @@ + + + + Title + + + + + + + + + + diff --git a/presentation.html b/presentation.html deleted file mode 100644 index b19c85a81..000000000 --- a/presentation.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - Title - - - - - - - - - From c850295aab8510779b60faa837697b9478f1eda0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Nov 2016 11:23:22 +0200 Subject: [PATCH 109/492] Add new diagram --- hexagonal/etc/hexagon.png | Bin 51788 -> 0 bytes hexagonal/etc/ports_and_adapters.png | Bin 0 -> 34860 bytes hexagonal/etc/ports_and_adapters.xml | 1 + hexagonal/etc/presentation.html | 24 ++++++++++++++++-------- 4 files changed, 17 insertions(+), 8 deletions(-) delete mode 100644 hexagonal/etc/hexagon.png create mode 100644 hexagonal/etc/ports_and_adapters.png create mode 100644 hexagonal/etc/ports_and_adapters.xml diff --git a/hexagonal/etc/hexagon.png b/hexagonal/etc/hexagon.png deleted file mode 100644 index e2d14e91dd692d888f85998087c881c559191900..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51788 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 diff --git a/hexagonal/etc/ports_and_adapters.png b/hexagonal/etc/ports_and_adapters.png new file mode 100644 index 0000000000000000000000000000000000000000..d285045dea68721c586bbfae5d303265f738eea0 GIT binary patch literal 34860 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 literal 0 HcmV?d00001 diff --git a/hexagonal/etc/ports_and_adapters.xml b/hexagonal/etc/ports_and_adapters.xml new file mode 100644 index 000000000..0e64414b8 --- /dev/null +++ b/hexagonal/etc/ports_and_adapters.xml @@ -0,0 +1 @@ +7Zpdk6I4FIZ/jbdbJAHEyx7nY/diqrqqd2tnLiOJSDUSK6ZHe3/9BkmUfFiDDqBM2TcNBwLxOe85nBOYoPl6/4XjzeorI7SYwIDsJ+jjBEKA4kj+qyzvtWUag9qQ8Zyok06Gl/w/qoyBsr7lhG6NEwVjhcg3pjFlZUlTYdgw52xnnrZkhXnXDc6oY3hJceFa/82JWNXWJApO9j9pnq30nUGgjixw+ppx9laq+00gWh7+6sNrrK+lzt+uMGG7hgl9mqA5Z0zUW+v9nBYVW42tHvf5zNHjvDktRZsBqB7wAxdvVM/4MC/xrlnIKW6qzRXd44yVE/RhQ3m+poLyk/X5ZPqwW+WCvmxwWo3aSYFI20qsC7kH5Ka6I+WC7s/OGhxZSI1RJi/N3+UpagBMFD4lL6D3dydnIa2lVcNRMFZGrASSHa99giQ3FCc/MzhKZmgaGcyOKBrMAPQwO2r7V5iFDrM549ThJgfJEKc/B7LMi2LOCsYP46oYg2kq7VvB2SttHCHxIo7ibhCGATARJshBqDNfk2AXoot+Lrpr4RFMk6UXXpwmdLHsCF5s6W/qwkMe+aEO4MW/GzwEPQmvJ3jT0cMDMxNeGA0GLxk7PDQ1H7VDKm82fnh2zoODwdPlz3jphdCUHoyGkx5oUeRdTS+iCQl99BK4QHFHxUoUWfQ89V5v9Fq0FXdOz9ZeMCC9Nk/ckjxVfa7cK1lJTWJ0n4tvje3vcjuotks5k2/Nne/6rJJ8zqsJHQ7Vd6PE6ZEtenJG7I2n1KhQBeYZFU0duJAbECMPRG3jtMAi/2HOwkdW3eGZ5XJ+Z7vECFjOqWevRjWbZOtCCJkXCu2Cvv7NzoUOjj7+7Ha+b1MwXOz7P6IefQwfPr7Qx33WNYNkR5s60nXuANkR9lnXDEIPWc8WNBvu2aJn+8v5JfDkF/V0Ac2nS3e5J/Hkntkj91yWe7S7O/U/OO/9/nzfWC5/+L6d70dfldsrOSEcbiXHs4R9ZeTUGdEXO41E2mX0TD3Rc1+Vue2gq6Mn6S963BX4Z8bF1hGBlLcwPW/GhFJGM4CUCRd5VsrdVDrz8FaoCpY8xcWTOrDOCSnOBWcH8YVmoYHzGDgNWYS+12pdxJe7SP/PVlKQZ1Q0ltVvtVEfXrRSojD3/w4NALvudd9hAN97x7ALQO6ywN90WwUDzqiS903h2CvFiZucZ32xcdvmv6RqMi6zFCtvjuZY4et851lN6g2N221+xAIv8Pb28RQHJhcwG04yOrU1uHxl6au0kLvBYz3dYOTi6S3doPF2irpKNAqe2I96mIIHWJ6Mr20XgF059dcuoD5axWEEoOsRQwDThwAuFECbfvE+Ox5dlxkCSB4CuFAAXbW8vpcRvldRHT4CfAK46WrhKAXQ5quzOxUAdAWAbrpkOEoBuE35E8Eb2Y//XuseVh+CPP1ZR+secvf0dXftkdMn9OjT/w== \ No newline at end of file diff --git a/hexagonal/etc/presentation.html b/hexagonal/etc/presentation.html index 46e26c550..74361ad27 100644 --- a/hexagonal/etc/presentation.html +++ b/hexagonal/etc/presentation.html @@ -60,29 +60,37 @@ Use Hexagonal Architecture pattern --- -# Diagram +# Concepts -.center[![Alt text](hexagon.png)] +* Ports are interfaces +* The ports that drive the application are called primary ports +* The ports that are driven by the application are called secondary ports --- # Concepts -* Ports are interfaces -* Adapters are implementations -* Driver ports vs driven ports +* Adapters are interface implementations +* Typically different adapters for testing and production are provided + +--- + +# Diagram + +.center[![Alt text](ports_and_adapters.png)] --- # Real world examples -* [Apache Isis](https://isis.apache.org/) +* [Apache Isis](https://isis.apache.org/) builds generic UI and REST API directly from the underlying domain objects --- -# Implementation example +# Tutorials -* http://java-design-patterns.com/patterns/hexagonal/ +* Blog http://java-design-patterns.com/blog/build-maintainable-systems-with-hexagonal-architecture/ +* Source code http://java-design-patterns.com/patterns/hexagonal/ + + + From 8d34ccf8270e19b96cb53e35dacfe1fc5ec8ca26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Mon, 26 Dec 2016 20:16:30 +0200 Subject: [PATCH 150/492] Add link to Proxy presentation. --- proxy/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxy/README.md b/proxy/README.md index ca63a6594..88adcfb21 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -37,6 +37,9 @@ are several common situations in which the Proxy pattern is applicable * Facilitate network connection * Count references to an object +## Presentations +* [Proxy](https://github.com/iluwatar/java-design-patterns/tree/master/proxy/etc/presentation.html) + ## Real world examples * [java.lang.reflect.Proxy](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html) From 0c48695fa51f0c761e30efd7c67a1f01cf0eaf62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 31 Dec 2016 10:23:32 +0200 Subject: [PATCH 151/492] Achieved milestone 1.14.0 --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- command/pom.xml | 2 +- composite/pom.xml | 2 +- dao/pom.xml | 2 +- data-mapper/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-asynchronous/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- execute-around/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- message-channel/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- module/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-mother/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- publish-subscribe/pom.xml | 2 +- queue-load-leveling/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- singleton/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strategy/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- twin/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 96 files changed, 99 insertions(+), 99 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index 0d7a31340..0bbb1e724 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index 25e00e377..cb6671348 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 abstract-factory diff --git a/adapter/pom.xml b/adapter/pom.xml index 0dac4ea8f..875013140 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 64fa86c23..1dac9f9db 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index a77e9f65f..24012790e 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index 0a6173420..7b19e3600 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index f13000f92..af00de9e4 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 aggregator-microservices diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index 24fb9bab9..5809754d9 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index 1e9905f1f..54f842a23 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index aa8fc29ca..051dd944f 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index 3a33969b9..38f7a7085 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index 1c2f037e0..8f4f45edc 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 async-method-invocation diff --git a/bridge/pom.xml b/bridge/pom.xml index 7b98867a0..5c5de45da 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 bridge diff --git a/builder/pom.xml b/builder/pom.xml index ddfc07aac..e8140f6ff 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index 5be756edf..13b911737 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 business-delegate diff --git a/caching/pom.xml b/caching/pom.xml index 121ea698a..5117d3a5d 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 caching diff --git a/callback/pom.xml b/callback/pom.xml index afb578ae2..54f8b046c 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 callback diff --git a/chain/pom.xml b/chain/pom.xml index affe2c945..d908f29bc 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 chain diff --git a/command/pom.xml b/command/pom.xml index 15f80a754..01cc6d054 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 command diff --git a/composite/pom.xml b/composite/pom.xml index 1a21d5034..0ae7194c9 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 composite diff --git a/dao/pom.xml b/dao/pom.xml index 0a26bd01b..f4aa88b0c 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 dao diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index eb342e9eb..3b43f845d 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 data-mapper diff --git a/decorator/pom.xml b/decorator/pom.xml index b8d52f66c..69415e212 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index 368e4d2bb..2eaf13640 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index 66f05381d..282cd73f2 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index 0a4ef9c7b..562f58094 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index 2b19be0df..d9d10b285 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index 2c81ff65e..be2e84bb4 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 event-aggregator diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index 0855736a9..2a442e2d0 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 event-asynchronous diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index 6ef837a93..1db5e2833 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 event-driven-architecture diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 96a17ffd6..5aaf18876 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 execute-around diff --git a/facade/pom.xml b/facade/pom.xml index 9af019df4..4df1f50d5 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index b861c9571..682188ab9 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index e27bd2444..4a64b9618 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index 69a6580cb..2dce8c7e9 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index 09306836b..ab656bd7b 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index 713732563..ec25ff611 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index 127a92b73..f787ef614 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index 51be506ee..c50bffb46 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 front-controller diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index 30a297488..bb06214a2 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index a02c049ca..5d23fb722 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index 77bf04549..086551328 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index c46aa9b39..39e0c242e 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 17100f9c4..97634e66d 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 iterator diff --git a/layers/pom.xml b/layers/pom.xml index 36b30aaf6..bf5142448 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index cc212b86d..9733fa912 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 lazy-loading diff --git a/mediator/pom.xml b/mediator/pom.xml index 84fc0c550..e7fbebd31 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 mediator diff --git a/memento/pom.xml b/memento/pom.xml index c22e5ec0d..25482d3be 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 memento diff --git a/message-channel/pom.xml b/message-channel/pom.xml index 85edd5b88..f98e816d5 100644 --- a/message-channel/pom.xml +++ b/message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 message-channel diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index e85f26115..2bf38c8c9 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 88176d5dc..06ebedc9d 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 model-view-presenter model-view-presenter diff --git a/module/pom.xml b/module/pom.xml index bc43e3e09..6349efb51 100644 --- a/module/pom.xml +++ b/module/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 module diff --git a/monad/pom.xml b/monad/pom.xml index 81a5b08e0..f310c34c9 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 monad diff --git a/monostate/pom.xml b/monostate/pom.xml index 1f300b729..956c51f1e 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index e27211074..616f1dd60 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index 98cd4d12f..a099e8e0c 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index b53587aa3..1a4679c4e 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 7e16ca000..00535901c 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0-SNAPSHOT + 1.14.0 naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index f31b10fe2..f8613cf70 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0-SNAPSHOT + 1.14.0 naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index 547e88268..aec9fd168 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0-SNAPSHOT + 1.14.0 naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index 344a234ac..1253d857e 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -15,7 +15,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 naked-objects @@ -367,17 +367,17 @@ ${project.groupId} naked-objects-dom - 1.14.0-SNAPSHOT + 1.14.0 ${project.groupId} naked-objects-fixture - 1.14.0-SNAPSHOT + 1.14.0 ${project.groupId} naked-objects-webapp - 1.14.0-SNAPSHOT + 1.14.0 diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 1a729ade9..3fad91c74 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0-SNAPSHOT + 1.14.0 naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index 89abb6d92..5843b9dd4 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 null-object diff --git a/object-mother/pom.xml b/object-mother/pom.xml index 91bdff8e2..325f8133b 100644 --- a/object-mother/pom.xml +++ b/object-mother/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 object-mother diff --git a/object-pool/pom.xml b/object-pool/pom.xml index dbd16330a..f501621f2 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 object-pool diff --git a/observer/pom.xml b/observer/pom.xml index ba849f4a4..de26431c9 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 observer diff --git a/page-object/pom.xml b/page-object/pom.xml index 0dd09bdbb..ed34129c5 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 page-object diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index 2e0d8c078..672c465b4 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 poison-pill diff --git a/pom.xml b/pom.xml index 52f24a500..29764d4b2 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 pom 2014 diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index 11fc40d4b..40b0f478b 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index 66f3de208..4d21bfd51 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index cc2d9ea42..da8c91f00 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 promise diff --git a/property/pom.xml b/property/pom.xml index 3842cfed7..c9fa0f395 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 property diff --git a/prototype/pom.xml b/prototype/pom.xml index 5093e9715..1f2da1b38 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index 323521bcf..18b39e555 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 proxy diff --git a/publish-subscribe/pom.xml b/publish-subscribe/pom.xml index 51b5a4903..9f861f5cc 100644 --- a/publish-subscribe/pom.xml +++ b/publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 publish-subscribe diff --git a/queue-load-leveling/pom.xml b/queue-load-leveling/pom.xml index 4c3dd8cdd..e895fd2f4 100644 --- a/queue-load-leveling/pom.xml +++ b/queue-load-leveling/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 queue-load-leveling diff --git a/reactor/pom.xml b/reactor/pom.xml index 09a2565cc..569bd0bd5 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index 1f7db8709..6c8972352 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 9e7465293..5e430296e 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index 327a7e960..b96f3b673 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 resource-acquisition-is-initialization diff --git a/semaphore/pom.xml b/semaphore/pom.xml index 4ee0edb9f..1542cb0f2 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 semaphore diff --git a/servant/pom.xml b/servant/pom.xml index 30c02d0b8..ef47754d5 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 servant diff --git a/service-layer/pom.xml b/service-layer/pom.xml index 74fd36624..0149d7fb0 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index 058e1b1bc..a1ae8ed63 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 service-locator diff --git a/singleton/pom.xml b/singleton/pom.xml index ebacac8cc..31e492fe9 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 singleton diff --git a/specification/pom.xml b/specification/pom.xml index 5d9498652..6f652088a 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 specification diff --git a/state/pom.xml b/state/pom.xml index 03f9401c7..9fb92b770 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index 3b4cd8018..2d3c20f16 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.14.0 step-builder diff --git a/strategy/pom.xml b/strategy/pom.xml index b1a3be675..bad2e34e1 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 strategy diff --git a/template-method/pom.xml b/template-method/pom.xml index 892c84a7c..7a021fbf3 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index 46b9f3a0d..ca53a90d3 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 thread-pool diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index e1902d78d..68c8ce464 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 tolerant-reader diff --git a/twin/pom.xml b/twin/pom.xml index 774b74fe8..77bf8de91 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 twin diff --git a/value-object/pom.xml b/value-object/pom.xml index 84bd29c6d..bd2103462 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index 6e8f60063..2c7fff555 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.14.0 visitor From 0c8bb1c22e04e1dfdf0c14fd8c8429b0973d727c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 31 Dec 2016 10:24:26 +0200 Subject: [PATCH 152/492] Set version for next development iteration --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- command/pom.xml | 2 +- composite/pom.xml | 2 +- dao/pom.xml | 2 +- data-mapper/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-asynchronous/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- execute-around/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- message-channel/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- module/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-mother/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- publish-subscribe/pom.xml | 2 +- queue-load-leveling/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- singleton/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strategy/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- twin/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 96 files changed, 99 insertions(+), 99 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index 0bbb1e724..85215a021 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index cb6671348..e3129f6f0 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT abstract-factory diff --git a/adapter/pom.xml b/adapter/pom.xml index 875013140..83462f28c 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 1dac9f9db..64b27f12d 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index 24012790e..3cb68099b 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index 7b19e3600..027105e7f 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index af00de9e4..a38975177 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 aggregator-microservices diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index 5809754d9..3bd2392fa 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index 54f842a23..d42b31933 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index 051dd944f..de2b3f099 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index 38f7a7085..8a9a6f379 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index 8f4f45edc..dc5b64404 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT async-method-invocation diff --git a/bridge/pom.xml b/bridge/pom.xml index 5c5de45da..ec04ff395 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT bridge diff --git a/builder/pom.xml b/builder/pom.xml index e8140f6ff..305de70bd 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index 13b911737..d5fde8ea3 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT business-delegate diff --git a/caching/pom.xml b/caching/pom.xml index 5117d3a5d..6d866eb03 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT caching diff --git a/callback/pom.xml b/callback/pom.xml index 54f8b046c..2b8d1fec6 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT callback diff --git a/chain/pom.xml b/chain/pom.xml index d908f29bc..81aaf7e1f 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT chain diff --git a/command/pom.xml b/command/pom.xml index 01cc6d054..e50be3e3d 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT command diff --git a/composite/pom.xml b/composite/pom.xml index 0ae7194c9..107502963 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT composite diff --git a/dao/pom.xml b/dao/pom.xml index f4aa88b0c..374a1c14c 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT dao diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index 3b43f845d..c23868a4e 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT data-mapper diff --git a/decorator/pom.xml b/decorator/pom.xml index 69415e212..51684065c 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index 2eaf13640..cf0349024 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index 282cd73f2..603bb2c05 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index 562f58094..0b0541b8f 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index d9d10b285..b15e76f88 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index be2e84bb4..3bf8c281b 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT event-aggregator diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index 2a442e2d0..9fecfa606 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT event-asynchronous diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index 1db5e2833..2ced1abda 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT event-driven-architecture diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 5aaf18876..acc36b4b4 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT execute-around diff --git a/facade/pom.xml b/facade/pom.xml index 4df1f50d5..0f1fa8688 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index 682188ab9..f356fc3b8 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index 4a64b9618..d6359ff03 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index 2dce8c7e9..e2635f228 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index ab656bd7b..8d815079c 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index ec25ff611..aa0c95796 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index f787ef614..2c210a0ca 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index c50bffb46..11802d2f5 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT front-controller diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index bb06214a2..4b3285ff1 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index 5d23fb722..2cf88b626 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index 086551328..2c23edff2 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index 39e0c242e..a932e10b4 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 97634e66d..3fcdd9852 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT iterator diff --git a/layers/pom.xml b/layers/pom.xml index bf5142448..13604cb0e 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index 9733fa912..2ed0a1020 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT lazy-loading diff --git a/mediator/pom.xml b/mediator/pom.xml index e7fbebd31..b9fda50a5 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT mediator diff --git a/memento/pom.xml b/memento/pom.xml index 25482d3be..e6cd095d9 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT memento diff --git a/message-channel/pom.xml b/message-channel/pom.xml index f98e816d5..98b2a0c2e 100644 --- a/message-channel/pom.xml +++ b/message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT message-channel diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index 2bf38c8c9..29823d9e8 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 06ebedc9d..6c43a0048 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT model-view-presenter model-view-presenter diff --git a/module/pom.xml b/module/pom.xml index 6349efb51..8920916cb 100644 --- a/module/pom.xml +++ b/module/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT module diff --git a/monad/pom.xml b/monad/pom.xml index f310c34c9..63d6431db 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT monad diff --git a/monostate/pom.xml b/monostate/pom.xml index 956c51f1e..bc025fdeb 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index 616f1dd60..34cc4ae8d 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index a099e8e0c..d68b016f9 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index 1a4679c4e..d42a2fdab 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 00535901c..39560b5c0 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0 + 1.15.0-SNAPSHOT naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index f8613cf70..a96c24626 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0 + 1.15.0-SNAPSHOT naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index aec9fd168..32ec4cd6b 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0 + 1.15.0-SNAPSHOT naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index 1253d857e..d8acdc745 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -15,7 +15,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT naked-objects @@ -367,17 +367,17 @@ ${project.groupId} naked-objects-dom - 1.14.0 + 1.15.0-SNAPSHOT ${project.groupId} naked-objects-fixture - 1.14.0 + 1.15.0-SNAPSHOT ${project.groupId} naked-objects-webapp - 1.14.0 + 1.15.0-SNAPSHOT diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 3fad91c74..7e6d3ffcd 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.14.0 + 1.15.0-SNAPSHOT naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index 5843b9dd4..2c494e3b7 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT null-object diff --git a/object-mother/pom.xml b/object-mother/pom.xml index 325f8133b..fc7d96a85 100644 --- a/object-mother/pom.xml +++ b/object-mother/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT object-mother diff --git a/object-pool/pom.xml b/object-pool/pom.xml index f501621f2..19ac48956 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT object-pool diff --git a/observer/pom.xml b/observer/pom.xml index de26431c9..bb313552c 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT observer diff --git a/page-object/pom.xml b/page-object/pom.xml index ed34129c5..35ee916a5 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT page-object diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index 672c465b4..e518649cf 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT poison-pill diff --git a/pom.xml b/pom.xml index 29764d4b2..5ddd3bf98 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT pom 2014 diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index 40b0f478b..957e18033 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index 4d21bfd51..dbc80614f 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index da8c91f00..a93ef2ba5 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT promise diff --git a/property/pom.xml b/property/pom.xml index c9fa0f395..4b28b9f54 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT property diff --git a/prototype/pom.xml b/prototype/pom.xml index 1f2da1b38..995757d5a 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index 18b39e555..f12db724c 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT proxy diff --git a/publish-subscribe/pom.xml b/publish-subscribe/pom.xml index 9f861f5cc..1586815c1 100644 --- a/publish-subscribe/pom.xml +++ b/publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT publish-subscribe diff --git a/queue-load-leveling/pom.xml b/queue-load-leveling/pom.xml index e895fd2f4..351f94906 100644 --- a/queue-load-leveling/pom.xml +++ b/queue-load-leveling/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT queue-load-leveling diff --git a/reactor/pom.xml b/reactor/pom.xml index 569bd0bd5..1d3aa22e7 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index 6c8972352..a46f6f5b2 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 5e430296e..5cae0466f 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index b96f3b673..ecf304ad2 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT resource-acquisition-is-initialization diff --git a/semaphore/pom.xml b/semaphore/pom.xml index 1542cb0f2..34b6bf629 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT semaphore diff --git a/servant/pom.xml b/servant/pom.xml index ef47754d5..fc59c795b 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT servant diff --git a/service-layer/pom.xml b/service-layer/pom.xml index 0149d7fb0..3d9e5e26f 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index a1ae8ed63..397955f8e 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT service-locator diff --git a/singleton/pom.xml b/singleton/pom.xml index 31e492fe9..8ddcb2131 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT singleton diff --git a/specification/pom.xml b/specification/pom.xml index 6f652088a..40584b7ca 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT specification diff --git a/state/pom.xml b/state/pom.xml index 9fb92b770..18a2608cd 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index 2d3c20f16..b33f48fb7 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.14.0 + 1.15.0-SNAPSHOT step-builder diff --git a/strategy/pom.xml b/strategy/pom.xml index bad2e34e1..c47281228 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT strategy diff --git a/template-method/pom.xml b/template-method/pom.xml index 7a021fbf3..4a40c89fb 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index ca53a90d3..a3b8d1fe6 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT thread-pool diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index 68c8ce464..da580631d 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT tolerant-reader diff --git a/twin/pom.xml b/twin/pom.xml index 77bf8de91..b9f6fb6ee 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT twin diff --git a/value-object/pom.xml b/value-object/pom.xml index bd2103462..ae18ed94a 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index 2c7fff555..2aeeb73b0 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.14.0 + 1.15.0-SNAPSHOT visitor From 29c5b80f199caf5d569549336b73b25ba9979d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 21 Jan 2017 12:56:42 +0200 Subject: [PATCH 153/492] #525 Add link to Queue-Based Load Leveling blog --- queue-load-leveling/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/queue-load-leveling/README.md b/queue-load-leveling/README.md index 1179e5985..126d19176 100644 --- a/queue-load-leveling/README.md +++ b/queue-load-leveling/README.md @@ -25,6 +25,9 @@ for both the task and the service. * This pattern is ideally suited to any type of application that uses services that may be subject to overloading. * This pattern might not be suitable if the application expects a response from the service with minimal latency. +## Tutorials +* [Queue-Based Load Leveling Pattern](http://java-design-patterns.com/blog/queue-load-leveling/) + ## Real world example * A Microsoft Azure web role stores data by using a separate storage service. If a large number of instances of the web role run concurrently, it is possible that the storage service could be overwhelmed and be unable to respond to requests quickly enough to prevent these requests from timing out or failing. From 115a85301c8a6a6c1db9413ceec1b09522f04a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 21 Jan 2017 13:37:16 +0200 Subject: [PATCH 154/492] #525 Add link to proxy blog --- proxy/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proxy/README.md b/proxy/README.md index 88adcfb21..17f23de50 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -37,6 +37,9 @@ are several common situations in which the Proxy pattern is applicable * Facilitate network connection * Count references to an object +## Tutorials +* [Controlling Access With Proxy Pattern](http://java-design-patterns.com/blog/controlling-access-with-proxy-pattern/) + ## Presentations * [Proxy](https://github.com/iluwatar/java-design-patterns/tree/master/proxy/etc/presentation.html) From d6fc28e120b8d8d0d8d065e7954a0f23a0a11459 Mon Sep 17 00:00:00 2001 From: leogtzr Date: Sat, 21 Jan 2017 15:47:54 -0700 Subject: [PATCH 155/492] Changing code to use interfaces instead of implementations. --- .../java/com/iluwatar/caching/LruCache.java | 2 +- .../iluwatar/factorykit/WeaponFactory.java | 3 +- .../iluwatar/hexagonal/banking/MongoBank.java | 3 +- .../database/MongoTicketRepository.java | 8 ++- .../layers/CakeBakingServiceImpl.java | 2 +- memory-dao-test/.springBeans | 16 +++++ memory-dao-test/pom.xml | 71 +++++++++++++++++++ .../src/main/java/com/memory/dao/App.java | 22 ++++++ .../main/java/com/memory/dao/AppConfig.java | 9 +++ .../main/java/com/memory/dao/db/Queries.java | 19 +++++ .../main/java/com/memory/dao/db/UserDAO.java | 11 +++ .../java/com/memory/dao/db/UserDAOImpl.java | 61 ++++++++++++++++ .../main/java/com/memory/dao/pojo/User.java | 38 ++++++++++ memory-dao-test/src/main/resources/beans.xml | 20 ++++++ .../src/main/resources/db-h2-config.xml | 18 +++++ .../src/main/resources/db/sql/create-db.sql | 7 ++ .../src/main/resources/db/sql/insert-data.sql | 3 + .../src/test/java/com/memory/dao/AppTest.java | 30 ++++++++ module/error.txt | 0 module/output.txt | 0 .../com/iluwatar/object/pool/ObjectPool.java | 5 +- .../com/iluwatar/semaphore/FruitBowl.java | 3 +- .../main/java/com/iluwatar/servant/App.java | 3 +- .../com/iluwatar/servant/ServantTest.java | 5 +- 24 files changed, 346 insertions(+), 13 deletions(-) create mode 100644 memory-dao-test/.springBeans create mode 100644 memory-dao-test/pom.xml create mode 100644 memory-dao-test/src/main/java/com/memory/dao/App.java create mode 100644 memory-dao-test/src/main/java/com/memory/dao/AppConfig.java create mode 100644 memory-dao-test/src/main/java/com/memory/dao/db/Queries.java create mode 100644 memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java create mode 100644 memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java create mode 100644 memory-dao-test/src/main/java/com/memory/dao/pojo/User.java create mode 100644 memory-dao-test/src/main/resources/beans.xml create mode 100755 memory-dao-test/src/main/resources/db-h2-config.xml create mode 100755 memory-dao-test/src/main/resources/db/sql/create-db.sql create mode 100755 memory-dao-test/src/main/resources/db/sql/insert-data.sql create mode 100644 memory-dao-test/src/test/java/com/memory/dao/AppTest.java create mode 100644 module/error.txt create mode 100644 module/output.txt diff --git a/caching/src/main/java/com/iluwatar/caching/LruCache.java b/caching/src/main/java/com/iluwatar/caching/LruCache.java index 2fc37ce44..fb9127bdc 100644 --- a/caching/src/main/java/com/iluwatar/caching/LruCache.java +++ b/caching/src/main/java/com/iluwatar/caching/LruCache.java @@ -167,7 +167,7 @@ public class LruCache { * Returns cache data in list form. */ public List getCacheDataInListForm() { - ArrayList listOfCacheData = new ArrayList<>(); + List listOfCacheData = new ArrayList<>(); Node temp = head; while (temp != null) { listOfCacheData.add(temp.userAccount); diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java index 4e8d1f77d..8ee9c6c39 100644 --- a/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java @@ -23,6 +23,7 @@ package com.iluwatar.factorykit; import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; @@ -48,7 +49,7 @@ public interface WeaponFactory { * @return factory with specified {@link Builder}s */ static WeaponFactory factory(Consumer consumer) { - HashMap> map = new HashMap<>(); + Map> map = new HashMap<>(); consumer.accept(map::put); return name -> map.get(name).get(); } diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java index fd0c1086f..7ccc829ed 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/MongoBank.java @@ -29,6 +29,7 @@ import com.mongodb.client.model.UpdateOptions; import org.bson.Document; import java.util.ArrayList; +import java.util.List; /** * Mongo based banking adapter @@ -110,7 +111,7 @@ public class MongoBank implements WireTransfers { @Override public int getFunds(String bankAccount) { Document search = new Document("_id", bankAccount); - ArrayList results = accountsCollection.find(search).limit(1).into(new ArrayList()); + List results = accountsCollection.find(search).limit(1).into(new ArrayList()); if (results.size() > 0) { return results.get(0).getInteger("funds"); } else { diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java index a68eee59a..ac747d4ea 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/MongoTicketRepository.java @@ -35,8 +35,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; /** * Mongo lottery ticket database @@ -142,7 +144,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { @Override public Optional findById(LotteryTicketId id) { Document find = new Document("ticketId", id.getId()); - ArrayList results = ticketsCollection.find(find).limit(1).into(new ArrayList()); + List results = ticketsCollection.find(find).limit(1).into(new ArrayList()); if (results.size() > 0) { LotteryTicket lotteryTicket = docToTicket(results.get(0)); return Optional.of(lotteryTicket); @@ -166,7 +168,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { @Override public Map findAll() { Map map = new HashMap<>(); - ArrayList docs = ticketsCollection.find(new Document()).into(new ArrayList()); + List docs = ticketsCollection.find(new Document()).into(new ArrayList()); for (Document doc: docs) { LotteryTicket lotteryTicket = docToTicket(doc); map.put(lotteryTicket.getId(), lotteryTicket); @@ -183,7 +185,7 @@ public class MongoTicketRepository implements LotteryTicketRepository { PlayerDetails playerDetails = new PlayerDetails(doc.getString("email"), doc.getString("bank"), doc.getString("phone")); int[] numArray = Arrays.asList(doc.getString("numbers").split(",")).stream().mapToInt(Integer::parseInt).toArray(); - HashSet numbers = new HashSet<>(); + Set numbers = new HashSet<>(); for (int num: numArray) { numbers.add(num); } diff --git a/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java b/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java index 85a362d90..e8deee73a 100644 --- a/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java +++ b/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java @@ -163,7 +163,7 @@ public class CakeBakingServiceImpl implements CakeBakingService { CakeToppingInfo cakeToppingInfo = new CakeToppingInfo(cake.getTopping().getId(), cake.getTopping().getName(), cake .getTopping().getCalories()); - ArrayList cakeLayerInfos = new ArrayList<>(); + List cakeLayerInfos = new ArrayList<>(); for (CakeLayer layer : cake.getLayers()) { cakeLayerInfos.add(new CakeLayerInfo(layer.getId(), layer.getName(), layer.getCalories())); } diff --git a/memory-dao-test/.springBeans b/memory-dao-test/.springBeans new file mode 100644 index 000000000..1fc985600 --- /dev/null +++ b/memory-dao-test/.springBeans @@ -0,0 +1,16 @@ + + + 1 + + + + + + + src/main/resources/beans.xml + + + + + + diff --git a/memory-dao-test/pom.xml b/memory-dao-test/pom.xml new file mode 100644 index 000000000..c8fb9b740 --- /dev/null +++ b/memory-dao-test/pom.xml @@ -0,0 +1,71 @@ + + 4.0.0 + com.memory.dao + memory-dao-test + 0.0.1 + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.12 + + + + org.apache.commons + commons-lang3 + 3.0 + + + + mysql + mysql-connector-java + 5.1.25 + + + + + com.h2database + h2 + 1.4.193 + + + + org.springframework + spring-core + 4.2.5.RELEASE + + + org.springframework + spring-beans + 4.2.5.RELEASE + + + org.springframework + spring-context + 4.2.5.RELEASE + + + + org.springframework + spring-jdbc + 4.2.5.RELEASE + + + + org.springframework + spring-test + 4.2.5.RELEASE + test + + + + + diff --git a/memory-dao-test/src/main/java/com/memory/dao/App.java b/memory-dao-test/src/main/java/com/memory/dao/App.java new file mode 100644 index 000000000..5f5b669ec --- /dev/null +++ b/memory-dao-test/src/main/java/com/memory/dao/App.java @@ -0,0 +1,22 @@ +package com.memory.dao; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import com.memory.dao.db.UserDAO; +import com.memory.dao.pojo.User; + +public class App { + public static void main(String[] args) { + + final ApplicationContext context = new ClassPathXmlApplicationContext( + "file:src/main/resources/beans.xml"); + + final UserDAO dao = (UserDAO)context.getBean("userDao"); + for (final User user : dao.findAll()) { + System.out.println(user); + } + + ((ClassPathXmlApplicationContext)context).close(); + } +} diff --git a/memory-dao-test/src/main/java/com/memory/dao/AppConfig.java b/memory-dao-test/src/main/java/com/memory/dao/AppConfig.java new file mode 100644 index 000000000..3ab6daeeb --- /dev/null +++ b/memory-dao-test/src/main/java/com/memory/dao/AppConfig.java @@ -0,0 +1,9 @@ +package com.memory.dao; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = {"com.memory.dao"}) +public class AppConfig { +} diff --git a/memory-dao-test/src/main/java/com/memory/dao/db/Queries.java b/memory-dao-test/src/main/java/com/memory/dao/db/Queries.java new file mode 100644 index 000000000..bae78e0c6 --- /dev/null +++ b/memory-dao-test/src/main/java/com/memory/dao/db/Queries.java @@ -0,0 +1,19 @@ +package com.memory.dao.db; + +public enum Queries { + + GET_USER("SELECT * FROM users WHERE name = :name"), + GET_ALL_USERS("SELECT * FROM users") + ; + + private final String query; + + Queries(final String query) { + this.query = query; + } + + public String get() { + return this.query; + } + +} diff --git a/memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java b/memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java new file mode 100644 index 000000000..ce21259ce --- /dev/null +++ b/memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java @@ -0,0 +1,11 @@ +package com.memory.dao.db; + +import com.memory.dao.pojo.User; +import java.util.List; + +public interface UserDAO { + + User findByName(String name); + List findAll(); + +} diff --git a/memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java b/memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java new file mode 100644 index 000000000..23385834a --- /dev/null +++ b/memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java @@ -0,0 +1,61 @@ +package com.memory.dao.db; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; + +import com.memory.dao.pojo.User; + +@Repository +public class UserDAOImpl implements UserDAO { + + private NamedParameterJdbcTemplate namedParameterJDBCTemplate; + + @Autowired + public void setNamedParameterJDBCTemplate(final NamedParameterJdbcTemplate namedParameterJDBCTemplate) { + this.namedParameterJDBCTemplate = namedParameterJDBCTemplate; + } + + @Override + public User findByName(final String name) { + final Map params = new HashMap<>(); + params.put("name", name); + + final User user = namedParameterJDBCTemplate. + queryForObject(Queries.GET_USER.get(), params, new UserMapper()); + + System.out.println("Found: " + user); + + return user; + } + + @Override + public List findAll() { + + Map params = new HashMap(); + + final List result = namedParameterJDBCTemplate.query(Queries.GET_ALL_USERS.get(), params, new UserMapper()); + + return result; + + } + + private static final class UserMapper implements RowMapper { + @Override + public User mapRow(final ResultSet rs, final int rowNum) throws SQLException { + final User user = new User(); + user.setId(rs.getInt("id")); + user.setName(rs.getString("name")); + user.setEmail(rs.getString("email")); + return user; + } + } + +} diff --git a/memory-dao-test/src/main/java/com/memory/dao/pojo/User.java b/memory-dao-test/src/main/java/com/memory/dao/pojo/User.java new file mode 100644 index 000000000..776df7a61 --- /dev/null +++ b/memory-dao-test/src/main/java/com/memory/dao/pojo/User.java @@ -0,0 +1,38 @@ +package com.memory.dao.pojo; + +public class User { + + private int id; + private String name; + private String email; + + public int getId() { + return id; + } + + public void setId(final int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(final String email) { + this.email = email; + } + + @Override + public String toString() { + return "User [id=" + id + ", name=" + name + ", email=" + email + "]"; + } + +} diff --git a/memory-dao-test/src/main/resources/beans.xml b/memory-dao-test/src/main/resources/beans.xml new file mode 100644 index 000000000..d6711afcc --- /dev/null +++ b/memory-dao-test/src/main/resources/beans.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/memory-dao-test/src/main/resources/db-h2-config.xml b/memory-dao-test/src/main/resources/db-h2-config.xml new file mode 100755 index 000000000..23e69d35d --- /dev/null +++ b/memory-dao-test/src/main/resources/db-h2-config.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/memory-dao-test/src/main/resources/db/sql/create-db.sql b/memory-dao-test/src/main/resources/db/sql/create-db.sql new file mode 100755 index 000000000..db19f033a --- /dev/null +++ b/memory-dao-test/src/main/resources/db/sql/create-db.sql @@ -0,0 +1,7 @@ +--DROP TABLE users IF EXISTS; + +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + name VARCHAR(30), + email VARCHAR(50) +); diff --git a/memory-dao-test/src/main/resources/db/sql/insert-data.sql b/memory-dao-test/src/main/resources/db/sql/insert-data.sql new file mode 100755 index 000000000..c0988e622 --- /dev/null +++ b/memory-dao-test/src/main/resources/db/sql/insert-data.sql @@ -0,0 +1,3 @@ +INSERT INTO users VALUES (1, 'mkyong', 'mkyong@gmail.com'); +INSERT INTO users VALUES (2, 'alex', 'alex@yahoo.com'); +INSERT INTO users VALUES (3, 'joel', 'joel@gmail.com'); \ No newline at end of file diff --git a/memory-dao-test/src/test/java/com/memory/dao/AppTest.java b/memory-dao-test/src/test/java/com/memory/dao/AppTest.java new file mode 100644 index 000000000..913d803b8 --- /dev/null +++ b/memory-dao-test/src/test/java/com/memory/dao/AppTest.java @@ -0,0 +1,30 @@ +package com.memory.dao; + +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.junit.runner.RunWith; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.ContextConfiguration; + +import com.memory.dao.db.UserDAO; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/beans.xml") +public class AppTest { + + @Autowired + private UserDAO dao; + + @Before + public void setUp() { + System.out.println(String.format("Dao is: %s", dao)); + } + + @Test + public void testApp() { + assertTrue(true); + } +} diff --git a/module/error.txt b/module/error.txt new file mode 100644 index 000000000..e69de29bb diff --git a/module/output.txt b/module/output.txt new file mode 100644 index 000000000..e69de29bb diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java index 790641690..510d9dc88 100644 --- a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java +++ b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java @@ -23,6 +23,7 @@ package com.iluwatar.object.pool; import java.util.HashSet; +import java.util.Set; /** * @@ -30,8 +31,8 @@ import java.util.HashSet; */ public abstract class ObjectPool { - private HashSet available = new HashSet<>(); - private HashSet inUse = new HashSet<>(); + private Set available = new HashSet<>(); + private Set inUse = new HashSet<>(); protected abstract T create(); diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java b/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java index 4f527f01c..a53672109 100644 --- a/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java +++ b/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java @@ -22,6 +22,7 @@ */ package com.iluwatar.semaphore; +import java.util.List; import java.util.ArrayList; /** @@ -29,7 +30,7 @@ import java.util.ArrayList; */ public class FruitBowl { - private ArrayList fruit = new ArrayList<>(); + private List fruit = new ArrayList<>(); /** * diff --git a/servant/src/main/java/com/iluwatar/servant/App.java b/servant/src/main/java/com/iluwatar/servant/App.java index 33a57e367..0e65e1de2 100644 --- a/servant/src/main/java/com/iluwatar/servant/App.java +++ b/servant/src/main/java/com/iluwatar/servant/App.java @@ -26,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.List; /** @@ -58,7 +59,7 @@ public class App { King k = new King(); Queen q = new Queen(); - ArrayList guests = new ArrayList<>(); + List guests = new ArrayList<>(); guests.add(k); guests.add(q); diff --git a/servant/src/test/java/com/iluwatar/servant/ServantTest.java b/servant/src/test/java/com/iluwatar/servant/ServantTest.java index e2e61e899..900ccc418 100644 --- a/servant/src/test/java/com/iluwatar/servant/ServantTest.java +++ b/servant/src/test/java/com/iluwatar/servant/ServantTest.java @@ -25,6 +25,7 @@ package com.iluwatar.servant; import org.junit.Test; import java.util.ArrayList; +import java.util.List; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; @@ -74,12 +75,12 @@ public class ServantTest { final Royalty badMoodRoyalty = mock(Royalty.class); when(badMoodRoyalty.getMood()).thenReturn(true); - final ArrayList goodCompany = new ArrayList<>(); + final List goodCompany = new ArrayList<>(); goodCompany.add(goodMoodRoyalty); goodCompany.add(goodMoodRoyalty); goodCompany.add(goodMoodRoyalty); - final ArrayList badCompany = new ArrayList<>(); + final List badCompany = new ArrayList<>(); goodCompany.add(goodMoodRoyalty); goodCompany.add(goodMoodRoyalty); goodCompany.add(badMoodRoyalty); From e26215578c3cbc978f4cb52cc872f9570ede9c62 Mon Sep 17 00:00:00 2001 From: leogtzr Date: Sat, 21 Jan 2017 15:49:29 -0700 Subject: [PATCH 156/492] Changing code to use interfaces instead of implementations. --- memory-dao-test/.springBeans | 16 ----- memory-dao-test/pom.xml | 71 ------------------- .../src/main/java/com/memory/dao/App.java | 22 ------ .../main/java/com/memory/dao/AppConfig.java | 9 --- .../main/java/com/memory/dao/db/Queries.java | 19 ----- .../main/java/com/memory/dao/db/UserDAO.java | 11 --- .../java/com/memory/dao/db/UserDAOImpl.java | 61 ---------------- .../main/java/com/memory/dao/pojo/User.java | 38 ---------- memory-dao-test/src/main/resources/beans.xml | 20 ------ .../src/main/resources/db-h2-config.xml | 18 ----- .../src/main/resources/db/sql/create-db.sql | 7 -- .../src/main/resources/db/sql/insert-data.sql | 3 - .../src/test/java/com/memory/dao/AppTest.java | 30 -------- 13 files changed, 325 deletions(-) delete mode 100644 memory-dao-test/.springBeans delete mode 100644 memory-dao-test/pom.xml delete mode 100644 memory-dao-test/src/main/java/com/memory/dao/App.java delete mode 100644 memory-dao-test/src/main/java/com/memory/dao/AppConfig.java delete mode 100644 memory-dao-test/src/main/java/com/memory/dao/db/Queries.java delete mode 100644 memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java delete mode 100644 memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java delete mode 100644 memory-dao-test/src/main/java/com/memory/dao/pojo/User.java delete mode 100644 memory-dao-test/src/main/resources/beans.xml delete mode 100755 memory-dao-test/src/main/resources/db-h2-config.xml delete mode 100755 memory-dao-test/src/main/resources/db/sql/create-db.sql delete mode 100755 memory-dao-test/src/main/resources/db/sql/insert-data.sql delete mode 100644 memory-dao-test/src/test/java/com/memory/dao/AppTest.java diff --git a/memory-dao-test/.springBeans b/memory-dao-test/.springBeans deleted file mode 100644 index 1fc985600..000000000 --- a/memory-dao-test/.springBeans +++ /dev/null @@ -1,16 +0,0 @@ - - - 1 - - - - - - - src/main/resources/beans.xml - - - - - - diff --git a/memory-dao-test/pom.xml b/memory-dao-test/pom.xml deleted file mode 100644 index c8fb9b740..000000000 --- a/memory-dao-test/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - 4.0.0 - com.memory.dao - memory-dao-test - 0.0.1 - - - UTF-8 - 1.7 - 1.7 - - - - - junit - junit - 4.12 - - - - org.apache.commons - commons-lang3 - 3.0 - - - - mysql - mysql-connector-java - 5.1.25 - - - - - com.h2database - h2 - 1.4.193 - - - - org.springframework - spring-core - 4.2.5.RELEASE - - - org.springframework - spring-beans - 4.2.5.RELEASE - - - org.springframework - spring-context - 4.2.5.RELEASE - - - - org.springframework - spring-jdbc - 4.2.5.RELEASE - - - - org.springframework - spring-test - 4.2.5.RELEASE - test - - - - - diff --git a/memory-dao-test/src/main/java/com/memory/dao/App.java b/memory-dao-test/src/main/java/com/memory/dao/App.java deleted file mode 100644 index 5f5b669ec..000000000 --- a/memory-dao-test/src/main/java/com/memory/dao/App.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.memory.dao; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import com.memory.dao.db.UserDAO; -import com.memory.dao.pojo.User; - -public class App { - public static void main(String[] args) { - - final ApplicationContext context = new ClassPathXmlApplicationContext( - "file:src/main/resources/beans.xml"); - - final UserDAO dao = (UserDAO)context.getBean("userDao"); - for (final User user : dao.findAll()) { - System.out.println(user); - } - - ((ClassPathXmlApplicationContext)context).close(); - } -} diff --git a/memory-dao-test/src/main/java/com/memory/dao/AppConfig.java b/memory-dao-test/src/main/java/com/memory/dao/AppConfig.java deleted file mode 100644 index 3ab6daeeb..000000000 --- a/memory-dao-test/src/main/java/com/memory/dao/AppConfig.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.memory.dao; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ComponentScan(basePackages = {"com.memory.dao"}) -public class AppConfig { -} diff --git a/memory-dao-test/src/main/java/com/memory/dao/db/Queries.java b/memory-dao-test/src/main/java/com/memory/dao/db/Queries.java deleted file mode 100644 index bae78e0c6..000000000 --- a/memory-dao-test/src/main/java/com/memory/dao/db/Queries.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.memory.dao.db; - -public enum Queries { - - GET_USER("SELECT * FROM users WHERE name = :name"), - GET_ALL_USERS("SELECT * FROM users") - ; - - private final String query; - - Queries(final String query) { - this.query = query; - } - - public String get() { - return this.query; - } - -} diff --git a/memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java b/memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java deleted file mode 100644 index ce21259ce..000000000 --- a/memory-dao-test/src/main/java/com/memory/dao/db/UserDAO.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.memory.dao.db; - -import com.memory.dao.pojo.User; -import java.util.List; - -public interface UserDAO { - - User findByName(String name); - List findAll(); - -} diff --git a/memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java b/memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java deleted file mode 100644 index 23385834a..000000000 --- a/memory-dao-test/src/main/java/com/memory/dao/db/UserDAOImpl.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.memory.dao.db; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import java.util.HashMap; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.stereotype.Repository; - -import com.memory.dao.pojo.User; - -@Repository -public class UserDAOImpl implements UserDAO { - - private NamedParameterJdbcTemplate namedParameterJDBCTemplate; - - @Autowired - public void setNamedParameterJDBCTemplate(final NamedParameterJdbcTemplate namedParameterJDBCTemplate) { - this.namedParameterJDBCTemplate = namedParameterJDBCTemplate; - } - - @Override - public User findByName(final String name) { - final Map params = new HashMap<>(); - params.put("name", name); - - final User user = namedParameterJDBCTemplate. - queryForObject(Queries.GET_USER.get(), params, new UserMapper()); - - System.out.println("Found: " + user); - - return user; - } - - @Override - public List findAll() { - - Map params = new HashMap(); - - final List result = namedParameterJDBCTemplate.query(Queries.GET_ALL_USERS.get(), params, new UserMapper()); - - return result; - - } - - private static final class UserMapper implements RowMapper { - @Override - public User mapRow(final ResultSet rs, final int rowNum) throws SQLException { - final User user = new User(); - user.setId(rs.getInt("id")); - user.setName(rs.getString("name")); - user.setEmail(rs.getString("email")); - return user; - } - } - -} diff --git a/memory-dao-test/src/main/java/com/memory/dao/pojo/User.java b/memory-dao-test/src/main/java/com/memory/dao/pojo/User.java deleted file mode 100644 index 776df7a61..000000000 --- a/memory-dao-test/src/main/java/com/memory/dao/pojo/User.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.memory.dao.pojo; - -public class User { - - private int id; - private String name; - private String email; - - public int getId() { - return id; - } - - public void setId(final int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(final String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(final String email) { - this.email = email; - } - - @Override - public String toString() { - return "User [id=" + id + ", name=" + name + ", email=" + email + "]"; - } - -} diff --git a/memory-dao-test/src/main/resources/beans.xml b/memory-dao-test/src/main/resources/beans.xml deleted file mode 100644 index d6711afcc..000000000 --- a/memory-dao-test/src/main/resources/beans.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/memory-dao-test/src/main/resources/db-h2-config.xml b/memory-dao-test/src/main/resources/db-h2-config.xml deleted file mode 100755 index 23e69d35d..000000000 --- a/memory-dao-test/src/main/resources/db-h2-config.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/memory-dao-test/src/main/resources/db/sql/create-db.sql b/memory-dao-test/src/main/resources/db/sql/create-db.sql deleted file mode 100755 index db19f033a..000000000 --- a/memory-dao-test/src/main/resources/db/sql/create-db.sql +++ /dev/null @@ -1,7 +0,0 @@ ---DROP TABLE users IF EXISTS; - -CREATE TABLE users ( - id INTEGER PRIMARY KEY, - name VARCHAR(30), - email VARCHAR(50) -); diff --git a/memory-dao-test/src/main/resources/db/sql/insert-data.sql b/memory-dao-test/src/main/resources/db/sql/insert-data.sql deleted file mode 100755 index c0988e622..000000000 --- a/memory-dao-test/src/main/resources/db/sql/insert-data.sql +++ /dev/null @@ -1,3 +0,0 @@ -INSERT INTO users VALUES (1, 'mkyong', 'mkyong@gmail.com'); -INSERT INTO users VALUES (2, 'alex', 'alex@yahoo.com'); -INSERT INTO users VALUES (3, 'joel', 'joel@gmail.com'); \ No newline at end of file diff --git a/memory-dao-test/src/test/java/com/memory/dao/AppTest.java b/memory-dao-test/src/test/java/com/memory/dao/AppTest.java deleted file mode 100644 index 913d803b8..000000000 --- a/memory-dao-test/src/test/java/com/memory/dao/AppTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.memory.dao; - -import static org.junit.Assert.assertTrue; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.junit.runner.RunWith; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.ContextConfiguration; - -import com.memory.dao.db.UserDAO; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("/beans.xml") -public class AppTest { - - @Autowired - private UserDAO dao; - - @Before - public void setUp() { - System.out.println(String.format("Dao is: %s", dao)); - } - - @Test - public void testApp() { - assertTrue(true); - } -} From c6d0d2855713b8f807911529312eb9ae625de594 Mon Sep 17 00:00:00 2001 From: leogtzr Date: Sun, 22 Jan 2017 11:06:57 -0700 Subject: [PATCH 157/492] Reverting initialization on demand holder idiom. --- .../src/main/java/com/iluwatar/singleton/IvoryTower.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java index ec23ba71b..37917bda8 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java @@ -32,12 +32,10 @@ public final class IvoryTower { */ private IvoryTower() {} - private static class IvoryTowerHolder { - /** + /** * Static to class instance of the class. */ - private static final IvoryTower INSTANCE = new IvoryTower(); - } + private static final IvoryTower INSTANCE = new IvoryTower(); /** * To be called by user to obtain instance of the class. @@ -45,6 +43,6 @@ public final class IvoryTower { * @return instance of the singleton. */ public static IvoryTower getInstance() { - return IvoryTowerHolder.INSTANCE; + return INSTANCE; } } From 26b79a5382dfa22f7ffb22eb7acdf71918e75e6f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:16:45 +0100 Subject: [PATCH 158/492] Update README.md Some additonal description, deleted wrong pumlid --- tls/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tls/README.md b/tls/README.md index 53db18400..9503267df 100644 --- a/tls/README.md +++ b/tls/README.md @@ -3,7 +3,7 @@ layout: pattern title: Thread Local Storage folder: tls permalink: /patterns/tls/ -pumlid: 5Sd13OGm30NHLg00uZlTc62HeCI9x6-s_ONJF6dMghd5AM5jAS3qdSZubwwA4aUuM1uAKQGyEg6CpZxSwUQ7jrEyNhfD1iJKwNql2Cr9aB-ci9vczFO7 +pumlid: categories: Concurrency tags: - Java @@ -11,12 +11,13 @@ tags: --- ## Intent -Securing variables global to a thread, i.e. class variables of the Runnable object, -against being spoiled by other threads using the same instance of the Runnable object +Securing variables global to a thread, i.e. class variables if a Callable object, +against being spoiled by other threads using the same instance of the Callable object ![alt text](./etc/tls.png "Thread Local Storage") ## Applicability Use the Thread Local Storage in any of the following situations -* when you use class variables in your Runnable Object that are not read-only +* when you use class variables in your Callable Object that are not read-only and you use the same Callable instance in more than one thread running in parallel +* when you use static variables in your Callable Object that are not read-only and more than one instances of the Callable may run in parallel threads. From e8fc3427c6b982d4b670024ea5ee70bb254db84b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:23:33 +0100 Subject: [PATCH 159/492] Update README.md no change of content. Improved text --- tls/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tls/README.md b/tls/README.md index 9503267df..904d7ee05 100644 --- a/tls/README.md +++ b/tls/README.md @@ -11,13 +11,12 @@ tags: --- ## Intent -Securing variables global to a thread, i.e. class variables if a Callable object, -against being spoiled by other threads using the same instance of the Callable object +Securing variables global to a thread against being spoiled by other threads. That is needed if you use class variables or static variables in your Callable object or Runnable object that are not read-only. ![alt text](./etc/tls.png "Thread Local Storage") ## Applicability Use the Thread Local Storage in any of the following situations -* when you use class variables in your Callable Object that are not read-only and you use the same Callable instance in more than one thread running in parallel -* when you use static variables in your Callable Object that are not read-only and more than one instances of the Callable may run in parallel threads. +* when you use class variables in your Callable / Runnalbe object that are not read-only and you use the same Callable instance in more than one thread running in parallel +* when you use static variables in your Callable / Runnable object that are not read-only and more than one instances of the Callable / Runnalbe may run in parallel threads. From c167f87ce5eeb3060ee708a160d15b9878e211bc Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:27:46 +0100 Subject: [PATCH 160/492] Delete tls.png --- tls/etc/tls.png | Bin 10307 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tls/etc/tls.png diff --git a/tls/etc/tls.png b/tls/etc/tls.png deleted file mode 100644 index bedea6cc8bc4eaff9f9f6d32f7b696f3123a756b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10307 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 From 3342851005e337be6f0a2e69495ab62ab788034d Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:28:17 +0100 Subject: [PATCH 161/492] Delete tls.ucls --- tls/etc/tls.ucls | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 tls/etc/tls.ucls diff --git a/tls/etc/tls.ucls b/tls/etc/tls.ucls deleted file mode 100644 index 5e21929e2..000000000 --- a/tls/etc/tls.ucls +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From c529e35791dce7c4dc78799928f24a67982eb2b1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:28:27 +0100 Subject: [PATCH 162/492] Delete tls.urm.puml --- tls/etc/tls.urm.puml | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 tls/etc/tls.urm.puml diff --git a/tls/etc/tls.urm.puml b/tls/etc/tls.urm.puml deleted file mode 100644 index 6425b7d33..000000000 --- a/tls/etc/tls.urm.puml +++ /dev/null @@ -1,28 +0,0 @@ -@startuml -package com.iluwatar.tls { - class App { - ~ dateList : List {static} - ~ exceptionList : List {static} - + App() - + main(args : String[]) {static} - } - class AppUgly { - ~ dateList : List {static} - ~ exceptionList : List {static} - + AppUgly() - + main(args : String[]) {static} - } - class DateFormatRunnable { - - dateValue : String - - df : ThreadLocal - + DateFormatRunnable(inDateFormat : String, inDateValue : String) - + run() - } - class DateFormatUglyRunnable { - - dateValue : String - - df : DateFormat - + DateFormatUglyRunnable(inDateFormat : String, inDateValue : String) - + run() - } -} -@enduml \ No newline at end of file From 65e047974c0bdaad2f93f89bb6d3994424f85f51 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:29:19 +0100 Subject: [PATCH 163/492] Create empty --- tls/etc/empty | 1 + 1 file changed, 1 insertion(+) create mode 100644 tls/etc/empty diff --git a/tls/etc/empty b/tls/etc/empty new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/tls/etc/empty @@ -0,0 +1 @@ + From 15913d6382d8baada2349e5dad1041ef4826c962 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:31:06 +0100 Subject: [PATCH 164/492] Add files via upload new uml diagramm after changes to the java classes --- tls/etc/tls.png | Bin 0 -> 34509 bytes tls/etc/tls.ucls | 79 +++++++++++++++++++++++++++++++++++++++++++ tls/etc/tls.urm.puml | 23 +++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 tls/etc/tls.png create mode 100644 tls/etc/tls.ucls create mode 100644 tls/etc/tls.urm.puml diff --git a/tls/etc/tls.png b/tls/etc/tls.png new file mode 100644 index 0000000000000000000000000000000000000000..442f39a0c730b6db350e1a2e0bffba1a2a60e8da GIT binary patch literal 34509 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 Su=8Tx-<3k&DUf*V`+op$;IV=L literal 0 HcmV?d00001 diff --git a/tls/etc/tls.ucls b/tls/etc/tls.ucls new file mode 100644 index 000000000..bd238346d --- /dev/null +++ b/tls/etc/tls.ucls @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tls/etc/tls.urm.puml b/tls/etc/tls.urm.puml new file mode 100644 index 000000000..d2eedb371 --- /dev/null +++ b/tls/etc/tls.urm.puml @@ -0,0 +1,23 @@ +@startuml +package com.iluwatar.tls { + class App { + + App() + + main(args : String[]) {static} + - printAndCountDates(res : Result) : int {static} + - printAndCountExceptions(res : Result) : int {static} + } + class DateFormatCallable { + - dateValue : String + - df : ThreadLocal + + DateFormatCallable(inDateFormat : String, inDateValue : String) + + call() : Result + } + class Result { + - dateList : List + - exceptionList : List + + Result() + + getDateList() : List + + getExceptionList() : List + } +} +@enduml \ No newline at end of file From 283f198ba89b7c003ce54ba7f49c95f751731bd6 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:32:26 +0100 Subject: [PATCH 165/492] Delete empty --- tls/etc/empty | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tls/etc/empty diff --git a/tls/etc/empty b/tls/etc/empty deleted file mode 100644 index 8b1378917..000000000 --- a/tls/etc/empty +++ /dev/null @@ -1 +0,0 @@ - From ed11c4c4f94a24b7ded3fdc22f79bc843516800a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:33:40 +0100 Subject: [PATCH 166/492] Delete App.java --- tls/src/main/java/com/iluwatar/tls/App.java | 108 -------------------- 1 file changed, 108 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/App.java diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java deleted file mode 100644 index b16aa1fc6..000000000 --- a/tls/src/main/java/com/iluwatar/tls/App.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.List; - -/** - * ThreadLocal pattern - *

    - * This App shows how to create an isolated space per each thread. In this - * example the usage of SimpleDateFormat is made to be thread-safe. This is an - * example of the ThreadLocal pattern. - *

    - * By applying the ThreadLocal pattern you can keep track of application - * instances or locale settings throughout the handling of a request. The - * ThreadLocal class works like a static variable, with the exception that it is - * only bound to the current thread! This allows us to use static variables in a - * thread-safe way. - *

    - * In Java, thread-local variables are implemented by the ThreadLocal class - * object. ThreadLocal holds variable of type T, which is accessible via get/set - * methods. - *

    - * SimpleDateFormat is one of the basic Java classes and is not thread-safe. If - * you do not isolate the instance of SimpleDateFormat per each thread then - * problems arise. These problems are described with the example {@link AppUgly} - * - */ -public class App { - // A list to collect the date values created in the the threads - static List dateList = Collections.synchronizedList(new ArrayList()); - - // A list to collect Exceptions thrown in the threads (should be none in - // this example) - static List exceptionList = Collections.synchronizedList(new ArrayList()); - - /** - * Program entry point - * - * @param args - * command line args - */ - public static void main(String[] args) { - int counterDateValues = 0; - int counterExceptions = 0; - - // Create a runnable - DateFormatRunnable runnableDf = new DateFormatRunnable("dd/MM/yyyy", "15/12/2015"); - // start 4 threads, each using the same Runnable instance - Thread t1 = new Thread(runnableDf); - Thread t2 = new Thread(runnableDf); - Thread t3 = new Thread(runnableDf); - Thread t4 = new Thread(runnableDf); - t1.start(); - t2.start(); - t3.start(); - t4.start(); - try { - t1.join(); - t2.join(); - t3.join(); - t4.join(); - } catch (InterruptedException e) { - // Action not coded here - } - for (Date dt : dateList) { - // a correct run should deliver 20 times 15.12.2015 - counterDateValues++; - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - // Formatted output of the date value: DD.MM.YYYY - System.out.println( - cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); - } - for (String ex : exceptionList) { - // a correct run shouldn't deliver any exception - counterExceptions++; - System.out.println(ex); - } - System.out.println("The List dateList contains " + counterDateValues + " date values"); - System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); - } -} From c5987485498a17998b97c4083323e11cb6a9a40a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:33:59 +0100 Subject: [PATCH 167/492] Delete AppUgly.java --- .../main/java/com/iluwatar/tls/AppUgly.java | 112 ------------------ 1 file changed, 112 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/AppUgly.java diff --git a/tls/src/main/java/com/iluwatar/tls/AppUgly.java b/tls/src/main/java/com/iluwatar/tls/AppUgly.java deleted file mode 100644 index 7025d42b7..000000000 --- a/tls/src/main/java/com/iluwatar/tls/AppUgly.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.List; - -/** - * - * This App shows an example for problems with global thread variables. A global - * thread variable is a variable defined as class variable of a - * XyzRunnable-Class. In this example in the class - * {@link DateFormatUglyRunnable} - *

    - * Example use case: A well known problem with threads are non thread-safe Java - * classes. One example is the class SimpleDateFormat. - *

    - * In the example an instance of SimpleDateFormat is created in the constructor - * of the Runnable. The constructor initializes a class variable with the - * instance. The Runnable only does convert a string date to a date format using - * the instance of SimpleDateFormat. It does this 5 times. - *

    - * In the example 4 threads are started to do the same. If you are lucky - * everything works well. But if you try more often you will happen to see - * Exceptions. And these Exceptions arise on arbitrary points of the run. - *

    - * The reason for this exceptions is: The threads try to use internal instance - * variables of the SimpleDateFormat instance at the same time (the date is - * stored internal as member variable during parsing and may be overwritten by - * another thread during a parse is still running) - *

    - * And even without Exceptions the run may not deliver the correct results. - * All date values should be the same after the run. Check it - * - */ -public class AppUgly { - // A list to collect the date values created in the the threads - static List dateList = Collections.synchronizedList(new ArrayList()); - // A list to collect Exceptions thrown in the threads - static List exceptionList = Collections.synchronizedList(new ArrayList()); - - /** - * Program entry point - * - * @param args - * command line args - */ - public static void main(String[] args) { - int counterDateValues = 0; - int counterExceptions = 0; - - // Prepare the Runnable - DateFormatUglyRunnable runnableDf = new DateFormatUglyRunnable("dd/MM/yyyy", "15/12/2015"); - - // 4 threads using the same Runnable - Thread t1 = new Thread(runnableDf); - Thread t2 = new Thread(runnableDf); - Thread t3 = new Thread(runnableDf); - Thread t4 = new Thread(runnableDf); - t1.start(); - t2.start(); - t3.start(); - t4.start(); - try { - t1.join(); - t2.join(); - t3.join(); - t4.join(); - } catch (InterruptedException e) { - // Action not coded here - } - for (Date dt : dateList) { - // a correct run should deliver 20 times 15.12.2015 - counterDateValues++; - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - // Formatted output of the date value: DD.MM.YYYY - System.out.println(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); - } - for (String ex : exceptionList) { - // a correct run shouldn't deliver any exception - counterExceptions++; - System.out.println(ex); - } - System.out.println("The List dateList contains " + counterDateValues + " date values"); - System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); - } -} From f170aaa42b2fafb9e6162810a3f529b5b114c499 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:34:12 +0100 Subject: [PATCH 168/492] Delete DateFormatRunnable.java --- .../com/iluwatar/tls/DateFormatRunnable.java | 84 ------------------- 1 file changed, 84 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java deleted file mode 100644 index d2009d21b..000000000 --- a/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; - -/** - * DateFormatRunnable converts string dates to a date format using - * SimpleDateFormat The date format and the date value will be passed to the - * Runnable by the constructor. The constructor creates a instance of - * SimpleDateFormat and stores it in a ThreadLocal class variable. For the - * complete description of the example see {@link App} - * - */ -public class DateFormatRunnable implements Runnable { - // class variables (members) - private ThreadLocal df; - private String dateValue; // for date Value Thread Local not needed - - /** - * The date format and the date value are passed to the constructor - * - * @param inDateFormat - * string date format string, e.g. "dd/MM/yyyy" - * @param inDateValue - * string date value, e.g. "21/06/2016" - */ - public DateFormatRunnable(String inDateFormat, String inDateValue) { - final String idf = inDateFormat; - this.df = new ThreadLocal() { - @Override - protected DateFormat initialValue() { - return new SimpleDateFormat(idf); - } - }; - this.dateValue = inDateValue; - } - - /** - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - System.out.println(Thread.currentThread() + " started executing..."); - - // Convert date value to date 5 times - for (int i = 1; i <= 5; i++) { - try { - // this is the statement where it is important to have the - // instance of SimpleDateFormat locally - // Create the date value and store it in dateList - App.dateList.add(this.df.get().parse(this.dateValue)); - } catch (Exception e) { - // write the Exception to a list and continue work - App.exceptionList.add(e.getClass() + ": " + e.getMessage()); - } - - } - - System.out.println(Thread.currentThread() + " finished executing"); - } -} From 7200329a6b05d1c54ec7f4cd89235199d29c4e5e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:38:20 +0100 Subject: [PATCH 169/492] Add files via upload Rework replaces previous version completely. Using ExecutorService. Use of result object instead of static variables. Ugly example is left out. --- tls/src/main/java/com/iluwatar/tls/App.java | 146 ++++++++++++++++++ .../com/iluwatar/tls/DateFormatCallable.java | 98 ++++++++++++ .../main/java/com/iluwatar/tls/Result.java | 40 +++++ 3 files changed, 284 insertions(+) create mode 100644 tls/src/main/java/com/iluwatar/tls/App.java create mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java create mode 100644 tls/src/main/java/com/iluwatar/tls/Result.java diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java new file mode 100644 index 000000000..80e87042c --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/App.java @@ -0,0 +1,146 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * ThreadLocal pattern + *

    + * This App shows how to create an isolated space per each thread. In this + * example the usage of SimpleDateFormat is made to be thread-safe. This is an + * example of the ThreadLocal pattern. + *

    + * By applying the ThreadLocal pattern you can keep track of application + * instances or locale settings throughout the handling of a request. The + * ThreadLocal class works like a static variable, with the exception that it is + * only bound to the current thread! This allows us to use static variables in a + * thread-safe way. + *

    + * In Java, thread-local variables are implemented by the ThreadLocal class + * object. ThreadLocal holds a variable of type T, which is accessible via get/set + * methods. + *

    + * SimpleDateFormat is one of the basic Java classes and is not thread-safe. If + * you do not isolate the instance of SimpleDateFormat per each thread then + * problems arise. + *

    + * App converts the String date value 15/12/2015 to the Date format using the + * Java class SimpleDateFormat. It does this 20 times using 4 threads, each doing + * it 5 times. With the usage of as ThreadLocal in DateFormatCallable everything + * runs well. But if you comment out the ThreadLocal variant (marked with "//TLTL") + * and comment in the non ThreadLocal variant (marked with "//NTLNTL") you can + * see what will happen without the ThreadLocal. Most likely you will get incorrect + * date values and / or exceptions. + *

    + * This example clearly show what will happen when using non thread-safe classes + * in a thread. In real life this may happen one in of 1.000 or 10.000 conversions + * and those are really hard to find errors. + * + * @author Thomas Bauer, 2017 + */ +public class App { + /** + * Program entry point + * + * @param args + * command line args + */ + public static void main(String[] args) { + int counterDateValues = 0; + int counterExceptions = 0; + + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start 4 threads, each using the same Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + + Future futureResult1 = executor.submit(callableDf); + Future futureResult2 = executor.submit(callableDf); + Future futureResult3 = executor.submit(callableDf); + Future futureResult4 = executor.submit(callableDf); + try { + Result[] result = new Result[4]; + result[0] = futureResult1.get(); + result[1] = futureResult2.get(); + result[2] = futureResult3.get(); + result[3] = futureResult4.get(); + + // Print results of thread executions (converted dates and raised exceptions) + // and count them + for (int i = 0; i < result.length; i++) { + counterDateValues = counterDateValues + printAndCountDates(result[i]); + counterExceptions = counterExceptions + printAndCountExceptions(result[i]); + } + + // a correct run should deliver 20 times 15.12.2015 + // and a correct run shouldn't deliver any exception + System.out.println("The List dateList contains " + counterDateValues + " date values"); + System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); + + } catch (Exception e) { + // no action here + } + executor.shutdown(); + } + + /** + * Print result (date values) of a thread execution and count dates + * + * @param res contains results of a thread execution + */ + private static int printAndCountDates(Result res) { + // a correct run should deliver 5 times 15.12.2015 per each thread + int counter = 0; + for (Date dt : res.getDateList()) { + counter++; + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + // Formatted output of the date value: DD.MM.YYYY + System.out.println( + cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); + } + return counter; + } + + /** + * Print result (exceptions) of a thread execution and count exceptions + * + * @param res contains results of a thread execution + * @return number of dates + */ + private static int printAndCountExceptions(Result res) { + // a correct run shouldn't deliver any exception + int counter = 0; + for (String ex : res.getExceptionList()) { + counter++; + System.out.println(ex); + } + return counter; + } +} diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java new file mode 100644 index 000000000..a28e24d4e --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.concurrent.Callable; + +/** + * DateFormatCallable converts string dates to a date format using + * SimpleDateFormat. The date format and the date value will be passed to the + * Callable by the constructor. The constructor creates a instance of + * SimpleDateFormat and stores it in a ThreadLocal class variable. For the + * complete description of the example see {@link App} + * + * You can comment out the code marked with //TLTL and comment in the + * code marked //NTLNTL. Then you can see what will happen if you do not + * use the ThreadLocal. For details see the description of {@link App} + * + * @author Thomas Bauer, 2017 + */ +public class DateFormatCallable implements Callable { + // class variables (members) + private ThreadLocal df; //TLTL + // private DateFormat df; //NTLNTL + + private String dateValue; // for dateValue Thread Local not needed + + + /** + * The date format and the date value are passed to the constructor + * + * @param inDateFormat + * string date format string, e.g. "dd/MM/yyyy" + * @param inDateValue + * string date value, e.g. "21/06/2016" + */ + public DateFormatCallable(String inDateFormat, String inDateValue) { + final String idf = inDateFormat; //TLTL + this.df = new ThreadLocal() { //TLTL + @Override //TLTL + protected DateFormat initialValue() { //TLTL + return new SimpleDateFormat(idf); //TLTL + } //TLTL + }; //TLTL + // this.df = new SimpleDateFormat(inDateFormat); //NTLNTL + this.dateValue = inDateValue; + } + + /** + * @see java.util.concurrent.Callable#call() + */ + @Override + public Result call() { + System.out.println(Thread.currentThread() + " started executing..."); + Result result = new Result(); + + // Convert date value to date 5 times + for (int i = 1; i <= 5; i++) { + try { + // this is the statement where it is important to have the + // instance of SimpleDateFormat locally + // Create the date value and store it in dateList + result.getDateList().add(this.df.get().parse(this.dateValue)); //TLTL +// result.getDateList().add(this.df.parse(this.dateValue)); //NTLNTL + } catch (Exception e) { + // write the Exception to a list and continue work + result.getExceptionList().add(e.getClass() + ": " + e.getMessage()); + } + + } + + System.out.println(Thread.currentThread() + " finished processing part of the thread"); + + return result; + } +} diff --git a/tls/src/main/java/com/iluwatar/tls/Result.java b/tls/src/main/java/com/iluwatar/tls/Result.java new file mode 100644 index 000000000..951a02a2f --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/Result.java @@ -0,0 +1,40 @@ +/* + * Fiducia IT AG, All rights reserved. Use is subject to license terms. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Result object that will be returned by the Callable {@link DateFormatCallable} + * used in {@link App} + * + * @author Thomas Bauer, 2017 + */ +public class Result { + // A list to collect the date values created in one thread + private List dateList = new ArrayList(); + + // A list to collect Exceptions thrown in one threads (should be none in + // this example) + private List exceptionList = new ArrayList(); + + /** + * + * @return List of date values collected within an thread execution + */ + public List getDateList() { + return dateList; + } + + /** + * + * @return List of exceptions thrown within an thread execution + */ + public List getExceptionList() { + return exceptionList; + } +} From 080965fb176f3156744fad4f3ab004e562bb1615 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:38:49 +0100 Subject: [PATCH 170/492] Delete DateFormatUglyRunnable.java --- .../iluwatar/tls/DateFormatUglyRunnable.java | 76 ------------------- 1 file changed, 76 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java deleted file mode 100644 index ca883a913..000000000 --- a/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; - -/** - * DateFormatUglyRunnable converts string dates to a date format using - * SimpleDateFormat. The date value and the date format will be passed to the - * Runnable by the constructor. The constructor creates an instance of - * SimpleDateFormat and stores it in a class variable. For the complete - * description of the example see {@link AppUgly} - * - */ -public class DateFormatUglyRunnable implements Runnable { - // class variables (members) - private DateFormat df; - private String dateValue; - - /** - * The date format and the date value are passed to the constructor - * - * @param inDateFormat - * string date format string, e.g. "dd/MM/yyyy" - * @param inDateValue - * string date value, e.g. "21/06/2016" - */ - public DateFormatUglyRunnable(String inDateFormat, String inDateValue) { - this.df = new SimpleDateFormat(inDateFormat); - this.dateValue = inDateValue; - } - - /** - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - System.out.println(Thread.currentThread() + " started executing..."); - - // Convert date value to date 5 times - for (int i = 1; i <= 5; i++) { - try { - // Create the date value and store it in dateList - AppUgly.dateList.add(this.df.parse(this.dateValue)); - } catch (Exception e) { - // write the Exception to a list and continue work - AppUgly.exceptionList.add(e.getClass() + ": " + e.getMessage()); - } - - } - - System.out.println(Thread.currentThread() + " finished executing"); - } -} From a8e2c157ded06ef6d149fa617e6cd4e9a1ce6a8f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:41:13 +0100 Subject: [PATCH 171/492] Add files via upload Test reworked completely. AppTest seperated. --- .../iluwatar/tls/DateFormatRunnableTest.java | 144 +++++++++++++++ ...FormatRunnableTestIncorrectDateFormat.java | 127 ++++++++++++++ .../DateFormatRunnableTestMultiThread.java | 164 ++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java new file mode 100644 index 000000000..d6105dc98 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java @@ -0,0 +1,144 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

    + * After a successful run 5 date values should be in the result object. All dates should have + * the same value (15.11.2015). To avoid problems with time zone not the date instances themselves + * are compared by the test. For the test the dates are converted into string format DD.MM.YYY + *

    + * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatRunnableTest { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdDateValues = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by the run of DateFormatRunnalbe + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + createdDateValues = convertDatesToString(result); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new ArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + */ + @Test + public void testDateValues() { + assertEquals(expectedDateValues, createdDateValues); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver 5 date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should deliver + * no exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java new file mode 100644 index 000000000..bae89f160 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java @@ -0,0 +1,127 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

    + * An incorrect formatted date is passed to the Callable + * After a successful run 0 date values and 5 exceptions should be in the result object. + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatRunnableTestIncorrectDateFormat { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdExceptions = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 0; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 5; + + /** + * Expected content of the list containing the exceptions created by the run of DateFormatRunnalbe + */ + List expectedExceptions = Arrays.asList("class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\""); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable. Pass a string date value not matching the format string + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15.12.2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + /** + * Test Exceptions after the run of DateFormatRunnalbe. A correct run should deliver 5 times the + * same exception + */ + @Test + public void testExecptions() { + assertEquals(expectedExceptions, result.getExceptionList()); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver no date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java new file mode 100644 index 000000000..354915209 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java @@ -0,0 +1,164 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is used by 4 threads in parallel + *

    + * After a successful run 5 date values should be in the result object of each thread. All dates + * should have the same value (15.11.2015). To avoid problems with time zone not the date instances + * themselves are compared by the test. For the test the dates are converted into string format DD.MM.YYY + *

    + * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatRunnableTestMultiThread { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable, one for each thread + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result[] result = new Result[4]; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + @SuppressWarnings("serial") + static class StringArrayList extends ArrayList { + /* nothing needed here */ + } + static List[] createdDateValues = new StringArrayList[4]; + + /** + * Expected number of date values in the date value list created by each thread + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by each thread + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by each thread + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult1 = executor.submit(callableDf); + Future futureResult2 = executor.submit(callableDf); + Future futureResult3 = executor.submit(callableDf); + Future futureResult4 = executor.submit(callableDf); + try { + result[0] = futureResult1.get(); + result[1] = futureResult2.get(); + result[2] = futureResult3.get(); + result[3] = futureResult4.get(); + for (int i = 0; i < result.length; i++) { + createdDateValues[i] = convertDatesToString(result[i]); + } + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new StringArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + * by each thread + */ + @Test + public void testDateValues() { + for (int i = 0; i < createdDateValues.length; i++) { + assertEquals(expectedDateValues, createdDateValues[i]); + } + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 date values by each thread + */ + @Test + public void testCounterDateValues() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterDateValues, result[i].getDateList().size()); + } + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver no exceptions + */ + @Test + public void testCounterExceptions() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterExceptions, result[i].getExceptionList().size()); + } + } +} From 453862cfc258539447568ad6459059e09829502e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:41:46 +0100 Subject: [PATCH 172/492] Delete AppTest.java --- .../test/java/com/iluwatar/tls/AppTest.java | 134 ------------------ 1 file changed, 134 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/AppTest.java diff --git a/tls/src/test/java/com/iluwatar/tls/AppTest.java b/tls/src/test/java/com/iluwatar/tls/AppTest.java deleted file mode 100644 index 09bb72c93..000000000 --- a/tls/src/test/java/com/iluwatar/tls/AppTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; - -/** - * - * Application test - * - * In this test {@link App} is executed. After the run of App the converted Data is available in - * the static lists created by the run of the app. - *

    - * After a successful run 20 date values should be in the date value list. All dates should have - * the same value (15.11.2015). To avoid problems with time zone not the date instances themselve - * are compared in the test. For the test the dates are converted in a string format DD.MM.YYY - *

    - * Additionally the number of list entries are tested for both the list with the date values - * and the list with the exceptions - * - */ -public class AppTest { - - // Class variables used in setup() have to be static because the Compiler wants the - // setup() method to be static - /** - * Number of date values in the list created by the run of App. Will be set in setup() - */ - static int actualCounterDateValues = 0; - - /** - * Number of exceptions in the list created by the run of App. Will be set in setup() - */ - static int actualCounterExceptions = 0; - - /** - * The date values created by the run of App. List will be filled in the setup() method - */ - static List actualDateValues = new ArrayList(); - - /** - * Expected number of date values in the date value list created by the run of App - */ - int expectedCounterDateValues = 20; - - /** - * Expected number of exceptions in the exception list created by the run of App. - */ - int expectedCounterExceptions = 0; - - /** - * Expected content of the list containing the date values created by the run of App - */ - List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", - "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", - "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); - - /** - * Run App. After this run the result is available in the static lists - */ - @BeforeClass - public static void setup() { - String[] args = {}; - App.main(args); - - // Prepare data created by the run of App for the tests - for (Date dt : App.dateList) { - actualCounterDateValues++; - // a correct run should deliver 20 times 15.12.2015 - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - // Convert date value to string format DD.MM.YYYY - actualDateValues.add( - cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); - } - for (@SuppressWarnings("unused") String exc : App.exceptionList) { - actualCounterExceptions++; - // a correct run should no exceptions - } - } - - /** - * Test date values after run of App. A correct run should deliver 20 times 15.12.2015 - */ - @Test - public void testDateValues() { - assertEquals(expectedDateValues, actualDateValues); - } - - /** - * Test number of dates in list after und of App. A correct run should deliver 20 date values - */ - @Test - public void testCounterDateValues() { - assertEquals(expectedCounterDateValues, actualCounterDateValues); - } - - /** - * Test number of Exceptions in list after und of App. A correct run should deliver no exceptions - */ - @Test - public void testCounterExceptions() { - assertEquals(expectedCounterExceptions, actualCounterExceptions); - } -} From 6202f3ab44700355f4bb7862ecaa74dd90acee33 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:42:16 +0100 Subject: [PATCH 173/492] Add files via upload --- .../test/java/com/iluwatar/tls/AppTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/AppTest.java diff --git a/tls/src/test/java/com/iluwatar/tls/AppTest.java b/tls/src/test/java/com/iluwatar/tls/AppTest.java new file mode 100644 index 000000000..073c0988a --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/AppTest.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import org.junit.Test; + +/** + * Tests that thread local storage example runs without errors. + * + * @author Thomas Bauer, January 2017 + * + */ +public class AppTest { + @Test + public void test() throws Exception { + String[] args = {}; + App.main(args); + } +} From 3324e1bc432867766182c7bb743af938093aa81f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:01:32 +0100 Subject: [PATCH 174/492] Update pom.xml added tls --- pom.xml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 52f24a500..12b4c3a06 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT pom 2014 @@ -50,7 +50,8 @@ abstract-factory - builder + tls + builder factory-method prototype singleton @@ -466,4 +467,9 @@ - \ No newline at end of file + + + Contact GitHub API Training Shop Blog About + + © 2017 GitHub, Inc. Terms Privacy Security Status Help + From 3d3dd58501e0911a4e431d4e9ab2a22b5777c6fe Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:08:11 +0100 Subject: [PATCH 175/492] Update pom.xml removed errors caused by copy code from master --- pom.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 12b4c3a06..42ae2626c 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ abstract-factory tls - builder + builder factory-method prototype singleton @@ -468,8 +468,3 @@ - - Contact GitHub API Training Shop Blog About - - © 2017 GitHub, Inc. Terms Privacy Security Status Help - From 59ea20745f468819894a440a42a0a76383225151 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:32:21 +0100 Subject: [PATCH 176/492] Delete DateFormatRunnableTest.java --- .../iluwatar/tls/DateFormatRunnableTest.java | 144 ------------------ 1 file changed, 144 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java deleted file mode 100644 index d6105dc98..000000000 --- a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * - * Test of the Callable - * - * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) - *

    - * After a successful run 5 date values should be in the result object. All dates should have - * the same value (15.11.2015). To avoid problems with time zone not the date instances themselves - * are compared by the test. For the test the dates are converted into string format DD.MM.YYY - *

    - * Additionally the number of list entries are tested for both the list with the date values - * and the list with the exceptions - * - * @author Thomas Bauer, January 2017 - * - */ -public class DateFormatRunnableTest { - - // Class variables used in setup() have to be static because setup() has to be static - /** - * Result object given back by DateFormatCallable - * -- Array with converted date values - * -- Array with thrown exceptions - */ - static Result result; - - /** - * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method - */ - static List createdDateValues = new ArrayList(); - - /** - * Expected number of date values in the date value list created by the run of DateFormatRunnalbe - */ - int expectedCounterDateValues = 5; - - /** - * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. - */ - int expectedCounterExceptions = 0; - - /** - * Expected content of the list containing the date values created by the run of DateFormatRunnalbe - */ - List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); - - /** - * Run Callable and prepare results for usage in the test methods - */ - @BeforeClass - public static void setup() { - // Create a callable - DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); - // start thread using the Callable instance - ExecutorService executor = Executors.newCachedThreadPool(); - Future futureResult = executor.submit(callableDf); - try { - result = futureResult.get(); - createdDateValues = convertDatesToString(result); - } catch (Exception e) { - fail("Setup failed: " + e); - } - executor.shutdown(); - } - - private static List convertDatesToString(Result res) { - // Format date value as DD.MM.YYYY - if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { - return null; - } - List returnList = new ArrayList(); - - for (Date dt : res.getDateList()) { - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); - } - return returnList; - } - - /** - * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 - */ - @Test - public void testDateValues() { - assertEquals(expectedDateValues, createdDateValues); - } - - /** - * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver 5 date values - */ - @Test - public void testCounterDateValues() { - assertEquals(expectedCounterDateValues, result.getDateList().size()); - } - - /** - * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should deliver - * no exceptions - */ - @Test - public void testCounterExceptions() { - assertEquals(expectedCounterExceptions, result.getExceptionList().size()); - } -} From 82f8460243e49d7bd5804acf3b1f1331284cc66c Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:32:32 +0100 Subject: [PATCH 177/492] Delete DateFormatRunnableTestIncorrectDateFormat.java --- ...FormatRunnableTestIncorrectDateFormat.java | 127 ------------------ 1 file changed, 127 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java deleted file mode 100644 index bae89f160..000000000 --- a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * - * Test of the Callable - * - * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) - *

    - * An incorrect formatted date is passed to the Callable - * After a successful run 0 date values and 5 exceptions should be in the result object. - * - * @author Thomas Bauer, January 2017 - * - */ -public class DateFormatRunnableTestIncorrectDateFormat { - - // Class variables used in setup() have to be static because setup() has to be static - /** - * Result object given back by DateFormatCallable - * -- Array with converted date values - * -- Array with thrown exceptions - */ - static Result result; - - /** - * The date values created by the run of DateFormatRunnalbe. List will be filled in the setup() method - */ - static List createdExceptions = new ArrayList(); - - /** - * Expected number of date values in the date value list created by the run of DateFormatRunnalbe - */ - int expectedCounterDateValues = 0; - - /** - * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. - */ - int expectedCounterExceptions = 5; - - /** - * Expected content of the list containing the exceptions created by the run of DateFormatRunnalbe - */ - List expectedExceptions = Arrays.asList("class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\""); - - /** - * Run Callable and prepare results for usage in the test methods - */ - @BeforeClass - public static void setup() { - // Create a callable. Pass a string date value not matching the format string - DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15.12.2015"); - // start thread using the Callable instance - ExecutorService executor = Executors.newCachedThreadPool(); - Future futureResult = executor.submit(callableDf); - try { - result = futureResult.get(); - } catch (Exception e) { - fail("Setup failed: " + e); - } - executor.shutdown(); - } - - /** - * Test Exceptions after the run of DateFormatRunnalbe. A correct run should deliver 5 times the - * same exception - */ - @Test - public void testExecptions() { - assertEquals(expectedExceptions, result.getExceptionList()); - } - - /** - * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver no date values - */ - @Test - public void testCounterDateValues() { - assertEquals(expectedCounterDateValues, result.getDateList().size()); - } - - /** - * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should - * deliver 5 exceptions - */ - @Test - public void testCounterExceptions() { - assertEquals(expectedCounterExceptions, result.getExceptionList().size()); - } -} From 2bbf84233e9c4d04e1c4fbe538f07d996f702458 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:32:44 +0100 Subject: [PATCH 178/492] Delete DateFormatRunnableTestMultiThread.java --- .../DateFormatRunnableTestMultiThread.java | 164 ------------------ 1 file changed, 164 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java deleted file mode 100644 index 354915209..000000000 --- a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * 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.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * - * Test of the Callable - * - * In this test {@link DateFormatCallable} is used by 4 threads in parallel - *

    - * After a successful run 5 date values should be in the result object of each thread. All dates - * should have the same value (15.11.2015). To avoid problems with time zone not the date instances - * themselves are compared by the test. For the test the dates are converted into string format DD.MM.YYY - *

    - * Additionally the number of list entries are tested for both the list with the date values - * and the list with the exceptions - * - * @author Thomas Bauer, January 2017 - * - */ -public class DateFormatRunnableTestMultiThread { - - // Class variables used in setup() have to be static because setup() has to be static - /** - * Result object given back by DateFormatCallable, one for each thread - * -- Array with converted date values - * -- Array with thrown exceptions - */ - static Result[] result = new Result[4]; - - /** - * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method - */ - @SuppressWarnings("serial") - static class StringArrayList extends ArrayList { - /* nothing needed here */ - } - static List[] createdDateValues = new StringArrayList[4]; - - /** - * Expected number of date values in the date value list created by each thread - */ - int expectedCounterDateValues = 5; - - /** - * Expected number of exceptions in the exception list created by each thread - */ - int expectedCounterExceptions = 0; - - /** - * Expected content of the list containing the date values created by each thread - */ - List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); - - /** - * Run Callable and prepare results for usage in the test methods - */ - @BeforeClass - public static void setup() { - // Create a callable - DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); - // start thread using the Callable instance - ExecutorService executor = Executors.newCachedThreadPool(); - Future futureResult1 = executor.submit(callableDf); - Future futureResult2 = executor.submit(callableDf); - Future futureResult3 = executor.submit(callableDf); - Future futureResult4 = executor.submit(callableDf); - try { - result[0] = futureResult1.get(); - result[1] = futureResult2.get(); - result[2] = futureResult3.get(); - result[3] = futureResult4.get(); - for (int i = 0; i < result.length; i++) { - createdDateValues[i] = convertDatesToString(result[i]); - } - } catch (Exception e) { - fail("Setup failed: " + e); - } - executor.shutdown(); - } - - private static List convertDatesToString(Result res) { - // Format date value as DD.MM.YYYY - if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { - return null; - } - List returnList = new StringArrayList(); - - for (Date dt : res.getDateList()) { - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); - } - return returnList; - } - - /** - * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 - * by each thread - */ - @Test - public void testDateValues() { - for (int i = 0; i < createdDateValues.length; i++) { - assertEquals(expectedDateValues, createdDateValues[i]); - } - } - - /** - * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should - * deliver 5 date values by each thread - */ - @Test - public void testCounterDateValues() { - for (int i = 0; i < result.length; i++) { - assertEquals(expectedCounterDateValues, result[i].getDateList().size()); - } - } - - /** - * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should - * deliver no exceptions - */ - @Test - public void testCounterExceptions() { - for (int i = 0; i < result.length; i++) { - assertEquals(expectedCounterExceptions, result[i].getExceptionList().size()); - } - } -} From ddac9dc6cb09a314111aed660c98c5b1fa12a9ce Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:34:13 +0100 Subject: [PATCH 179/492] Add files via upload Changed the classname part "runnable" to "callable" --- .../iluwatar/tls/DateFormatCallableTest.java | 144 +++++++++++++++ ...FormatCallableTestIncorrectDateFormat.java | 127 ++++++++++++++ .../DateFormatCallableTestMultiThread.java | 164 ++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java new file mode 100644 index 000000000..b4f24be9b --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java @@ -0,0 +1,144 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

    + * After a successful run 5 date values should be in the result object. All dates should have + * the same value (15.11.2015). To avoid problems with time zone not the date instances themselves + * are compared by the test. For the test the dates are converted into string format DD.MM.YYY + *

    + * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatCallableTest { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdDateValues = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by the run of DateFormatRunnalbe + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + createdDateValues = convertDatesToString(result); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new ArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + */ + @Test + public void testDateValues() { + assertEquals(expectedDateValues, createdDateValues); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver 5 date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should deliver + * no exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java new file mode 100644 index 000000000..e0a1507e9 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java @@ -0,0 +1,127 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

    + * An incorrect formatted date is passed to the Callable + * After a successful run 0 date values and 5 exceptions should be in the result object. + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatCallableTestIncorrectDateFormat { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdExceptions = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 0; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 5; + + /** + * Expected content of the list containing the exceptions created by the run of DateFormatRunnalbe + */ + List expectedExceptions = Arrays.asList("class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\""); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable. Pass a string date value not matching the format string + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15.12.2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + /** + * Test Exceptions after the run of DateFormatRunnalbe. A correct run should deliver 5 times the + * same exception + */ + @Test + public void testExecptions() { + assertEquals(expectedExceptions, result.getExceptionList()); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver no date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java new file mode 100644 index 000000000..635d6f25a --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java @@ -0,0 +1,164 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * 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.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is used by 4 threads in parallel + *

    + * After a successful run 5 date values should be in the result object of each thread. All dates + * should have the same value (15.11.2015). To avoid problems with time zone not the date instances + * themselves are compared by the test. For the test the dates are converted into string format DD.MM.YYY + *

    + * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatCallableTestMultiThread { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable, one for each thread + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result[] result = new Result[4]; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + @SuppressWarnings("serial") + static class StringArrayList extends ArrayList { + /* nothing needed here */ + } + static List[] createdDateValues = new StringArrayList[4]; + + /** + * Expected number of date values in the date value list created by each thread + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by each thread + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by each thread + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult1 = executor.submit(callableDf); + Future futureResult2 = executor.submit(callableDf); + Future futureResult3 = executor.submit(callableDf); + Future futureResult4 = executor.submit(callableDf); + try { + result[0] = futureResult1.get(); + result[1] = futureResult2.get(); + result[2] = futureResult3.get(); + result[3] = futureResult4.get(); + for (int i = 0; i < result.length; i++) { + createdDateValues[i] = convertDatesToString(result[i]); + } + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new StringArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + * by each thread + */ + @Test + public void testDateValues() { + for (int i = 0; i < createdDateValues.length; i++) { + assertEquals(expectedDateValues, createdDateValues[i]); + } + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 date values by each thread + */ + @Test + public void testCounterDateValues() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterDateValues, result[i].getDateList().size()); + } + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver no exceptions + */ + @Test + public void testCounterExceptions() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterExceptions, result[i].getExceptionList().size()); + } + } +} From a1ff55b462496ab205ab817748d77c066da27561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 11 Feb 2017 21:46:56 +0200 Subject: [PATCH 180/492] #190 Regenerate puml files --- builder/etc/builder.urm.puml | 6 +-- .../etc/business-delegate.urm.puml | 2 +- chain/etc/chain.urm.puml | 2 +- dao/etc/dao.urm.puml | 3 +- .../etc/event-driven-architecture.urm.puml | 2 +- flux/etc/flux.urm.puml | 4 +- hexagonal/etc/hexagonal.urm.puml | 16 +++++--- hexagonal/etc/ports_and_adapters.xml | 24 ++++++++++++ hexagonal/etc/presentation.html | 24 ++++++++++++ .../etc/intercepting-filter.urm.puml | 2 +- lazy-loading/etc/lazy-loading.urm.puml | 2 +- module/error.txt | 23 +++++++++++ module/etc/module.urm.puml | 4 +- module/output.txt | 23 +++++++++++ object-mother/etc/object-mother.urm.puml | 38 +++++++++---------- object-pool/etc/object-pool.urm.puml | 4 +- poison-pill/etc/poison-pill.urm.puml | 2 +- promise/etc/promise.urm.puml | 2 +- proxy/etc/presentation.html | 24 ++++++++++++ proxy/etc/proxy-concept.xml | 24 ++++++++++++ .../etc/reader-writer-lock.urm.puml | 2 +- semaphore/etc/semaphore.urm.puml | 4 +- state/etc/state.urm.puml | 2 +- step-builder/etc/step-builder.urm.puml | 4 +- 24 files changed, 195 insertions(+), 48 deletions(-) diff --git a/builder/etc/builder.urm.puml b/builder/etc/builder.urm.puml index 631c62cc4..df8d73f36 100644 --- a/builder/etc/builder.urm.puml +++ b/builder/etc/builder.urm.puml @@ -86,15 +86,15 @@ package com.iluwatar.builder { + values() : Weapon[] {static} } } -Hero --> "-profession" Profession Builder ..+ Hero +Hero --> "-profession" Profession Hero --> "-armor" Armor +Builder --> "-hairColor" HairColor Builder --> "-weapon" Weapon Builder --> "-hairType" HairType -Builder --> "-hairColor" HairColor Hero --> "-hairColor" HairColor Builder --> "-profession" Profession -Hero --> "-weapon" Weapon Hero --> "-hairType" HairType +Hero --> "-weapon" Weapon Builder --> "-armor" Armor @enduml \ No newline at end of file diff --git a/business-delegate/etc/business-delegate.urm.puml b/business-delegate/etc/business-delegate.urm.puml index e78b147e0..40aa2d6f0 100644 --- a/business-delegate/etc/business-delegate.urm.puml +++ b/business-delegate/etc/business-delegate.urm.puml @@ -46,8 +46,8 @@ package com.iluwatar.business.delegate { + values() : ServiceType[] {static} } } -BusinessDelegate --> "-serviceType" ServiceType BusinessLookup --> "-ejbService" EjbService +BusinessDelegate --> "-serviceType" ServiceType Client --> "-businessDelegate" BusinessDelegate BusinessDelegate --> "-businessService" BusinessService BusinessDelegate --> "-lookupService" BusinessLookup diff --git a/chain/etc/chain.urm.puml b/chain/etc/chain.urm.puml index 3add4037d..4a2f6a188 100644 --- a/chain/etc/chain.urm.puml +++ b/chain/etc/chain.urm.puml @@ -53,8 +53,8 @@ package com.iluwatar.chain { } } RequestHandler --> "-next" RequestHandler -OrcKing --> "-chain" RequestHandler Request --> "-requestType" RequestType +OrcKing --> "-chain" RequestHandler OrcCommander --|> RequestHandler OrcOfficer --|> RequestHandler OrcSoldier --|> RequestHandler diff --git a/dao/etc/dao.urm.puml b/dao/etc/dao.urm.puml index 2b3f7fca6..b0a5b2c54 100644 --- a/dao/etc/dao.urm.puml +++ b/dao/etc/dao.urm.puml @@ -34,9 +34,10 @@ package com.iluwatar.dao { + getById(int) : Optional {abstract} + update(Customer) : boolean {abstract} } - interface CustomerSchemaSql { + class CustomerSchemaSql { + CREATE_SCHEMA_SQL : String {static} + DELETE_SCHEMA_SQL : String {static} + - CustomerSchemaSql() } class DbCustomerDao { - dataSource : DataSource diff --git a/event-driven-architecture/etc/event-driven-architecture.urm.puml b/event-driven-architecture/etc/event-driven-architecture.urm.puml index 6b67f0a0e..2eb79e438 100644 --- a/event-driven-architecture/etc/event-driven-architecture.urm.puml +++ b/event-driven-architecture/etc/event-driven-architecture.urm.puml @@ -54,8 +54,8 @@ package com.iluwatar.eda { + main(args : String[]) {static} } } -UserCreatedEvent --> "-user" User UserUpdatedEvent --> "-user" User +UserCreatedEvent --> "-user" User AbstractEvent ..|> Event UserCreatedEvent --|> AbstractEvent UserUpdatedEvent --|> AbstractEvent diff --git a/flux/etc/flux.urm.puml b/flux/etc/flux.urm.puml index 40637d624..11ac26d60 100644 --- a/flux/etc/flux.urm.puml +++ b/flux/etc/flux.urm.puml @@ -99,15 +99,15 @@ package com.iluwatar.flux.dispatcher { } } MenuAction --> "-menuItem" MenuItem -MenuStore --> "-selected" MenuItem Action --> "-type" ActionType Dispatcher --> "-instance" Dispatcher +MenuStore --> "-selected" MenuItem ContentView --> "-content" Content Dispatcher --> "-stores" Store MenuView --> "-selected" MenuItem Store --> "-views" View -ContentStore --> "-content" Content ContentAction --> "-content" Content +ContentStore --> "-content" Content ContentAction --|> Action MenuAction --|> Action ContentStore --|> Store diff --git a/hexagonal/etc/hexagonal.urm.puml b/hexagonal/etc/hexagonal.urm.puml index f6dd970c0..9ca6e6f9f 100644 --- a/hexagonal/etc/hexagonal.urm.puml +++ b/hexagonal/etc/hexagonal.urm.puml @@ -11,9 +11,13 @@ package com.iluwatar.hexagonal.service { class ConsoleLottery { - LOGGER : Logger {static} + ConsoleLottery() + - addFundsToLotteryAccount(bank : WireTransfers, scanner : Scanner) {static} + - checkTicket(service : LotteryService, scanner : Scanner) {static} + main(args : String[]) {static} - printMainMenu() {static} + - queryLotteryAccountFunds(bank : WireTransfers, scanner : Scanner) {static} - readString(scanner : Scanner) : String {static} + - submitTicket(service : LotteryService, scanner : Scanner) {static} } } package com.iluwatar.hexagonal.mongo { @@ -252,16 +256,16 @@ package com.iluwatar.hexagonal.eventlog { + ticketWon(details : PlayerDetails, prizeAmount : int) } } -LotteryAdministration --> "-wireTransfers" WireTransfers -LotteryTicket --> "-id" LotteryTicketId LotteryTicket --> "-playerDetails" PlayerDetails -LotteryService --> "-notifications" LotteryEventLog -LotteryAdministration --> "-repository" LotteryTicketRepository -LotteryTicket --> "-lotteryNumbers" LotteryNumbers MongoEventLog --> "-stdOutEventLog" StdOutEventLog LotteryService --> "-wireTransfers" WireTransfers -SampleData --> "-PLAYERS" PlayerDetails LotteryAdministration --> "-notifications" LotteryEventLog +LotteryAdministration --> "-wireTransfers" WireTransfers +LotteryService --> "-notifications" LotteryEventLog +LotteryTicket --> "-id" LotteryTicketId +LotteryAdministration --> "-repository" LotteryTicketRepository +LotteryTicket --> "-lotteryNumbers" LotteryNumbers +SampleData --> "-PLAYERS" PlayerDetails RandomNumberGenerator ..+ LotteryNumbers LotteryService --> "-repository" LotteryTicketRepository CheckResult ..+ LotteryTicketCheckResult diff --git a/hexagonal/etc/ports_and_adapters.xml b/hexagonal/etc/ports_and_adapters.xml index 0e64414b8..9df3173d9 100644 --- a/hexagonal/etc/ports_and_adapters.xml +++ b/hexagonal/etc/ports_and_adapters.xml @@ -1 +1,25 @@ + 7Zpdk6I4FIZ/jbdbJAHEyx7nY/diqrqqd2tnLiOJSDUSK6ZHe3/9BkmUfFiDDqBM2TcNBwLxOe85nBOYoPl6/4XjzeorI7SYwIDsJ+jjBEKA4kj+qyzvtWUag9qQ8Zyok06Gl/w/qoyBsr7lhG6NEwVjhcg3pjFlZUlTYdgw52xnnrZkhXnXDc6oY3hJceFa/82JWNXWJApO9j9pnq30nUGgjixw+ppx9laq+00gWh7+6sNrrK+lzt+uMGG7hgl9mqA5Z0zUW+v9nBYVW42tHvf5zNHjvDktRZsBqB7wAxdvVM/4MC/xrlnIKW6qzRXd44yVE/RhQ3m+poLyk/X5ZPqwW+WCvmxwWo3aSYFI20qsC7kH5Ka6I+WC7s/OGhxZSI1RJi/N3+UpagBMFD4lL6D3dydnIa2lVcNRMFZGrASSHa99giQ3FCc/MzhKZmgaGcyOKBrMAPQwO2r7V5iFDrM549ThJgfJEKc/B7LMi2LOCsYP46oYg2kq7VvB2SttHCHxIo7ibhCGATARJshBqDNfk2AXoot+Lrpr4RFMk6UXXpwmdLHsCF5s6W/qwkMe+aEO4MW/GzwEPQmvJ3jT0cMDMxNeGA0GLxk7PDQ1H7VDKm82fnh2zoODwdPlz3jphdCUHoyGkx5oUeRdTS+iCQl99BK4QHFHxUoUWfQ89V5v9Fq0FXdOz9ZeMCC9Nk/ckjxVfa7cK1lJTWJ0n4tvje3vcjuotks5k2/Nne/6rJJ8zqsJHQ7Vd6PE6ZEtenJG7I2n1KhQBeYZFU0duJAbECMPRG3jtMAi/2HOwkdW3eGZ5XJ+Z7vECFjOqWevRjWbZOtCCJkXCu2Cvv7NzoUOjj7+7Ha+b1MwXOz7P6IefQwfPr7Qx33WNYNkR5s60nXuANkR9lnXDEIPWc8WNBvu2aJn+8v5JfDkF/V0Ac2nS3e5J/Hkntkj91yWe7S7O/U/OO/9/nzfWC5/+L6d70dfldsrOSEcbiXHs4R9ZeTUGdEXO41E2mX0TD3Rc1+Vue2gq6Mn6S963BX4Z8bF1hGBlLcwPW/GhFJGM4CUCRd5VsrdVDrz8FaoCpY8xcWTOrDOCSnOBWcH8YVmoYHzGDgNWYS+12pdxJe7SP/PVlKQZ1Q0ltVvtVEfXrRSojD3/w4NALvudd9hAN97x7ALQO6ywN90WwUDzqiS903h2CvFiZucZ32xcdvmv6RqMi6zFCtvjuZY4et851lN6g2N221+xAIv8Pb28RQHJhcwG04yOrU1uHxl6au0kLvBYz3dYOTi6S3doPF2irpKNAqe2I96mIIHWJ6Mr20XgF059dcuoD5axWEEoOsRQwDThwAuFECbfvE+Ox5dlxkCSB4CuFAAXbW8vpcRvldRHT4CfAK46WrhKAXQ5quzOxUAdAWAbrpkOEoBuE35E8Eb2Y//XuseVh+CPP1ZR+secvf0dXftkdMn9OjT/w== \ No newline at end of file diff --git a/hexagonal/etc/presentation.html b/hexagonal/etc/presentation.html index 74361ad27..5c6d1d0a5 100644 --- a/hexagonal/etc/presentation.html +++ b/hexagonal/etc/presentation.html @@ -1,3 +1,27 @@ + diff --git a/intercepting-filter/etc/intercepting-filter.urm.puml b/intercepting-filter/etc/intercepting-filter.urm.puml index 2b090cfff..5c1e79ee4 100644 --- a/intercepting-filter/etc/intercepting-filter.urm.puml +++ b/intercepting-filter/etc/intercepting-filter.urm.puml @@ -77,8 +77,8 @@ package com.iluwatar.intercepting.filter { } AbstractFilter --> "-next" Filter DListener --+ Target -FilterManager --> "-filterChain" FilterChain FilterChain --> "-chain" Filter +FilterManager --> "-filterChain" FilterChain AbstractFilter ..|> Filter AddressFilter --|> AbstractFilter ContactFilter --|> AbstractFilter diff --git a/lazy-loading/etc/lazy-loading.urm.puml b/lazy-loading/etc/lazy-loading.urm.puml index e982cb0d3..aaf49f1df 100644 --- a/lazy-loading/etc/lazy-loading.urm.puml +++ b/lazy-loading/etc/lazy-loading.urm.puml @@ -34,7 +34,7 @@ package com.iluwatar.lazy.loading { + get() : Heavy } } -HolderNaive --> "-heavy" Heavy HolderThreadSafe --> "-heavy" Heavy +HolderNaive --> "-heavy" Heavy HeavyFactory --> "-heavyInstance" Heavy @enduml \ No newline at end of file diff --git a/module/error.txt b/module/error.txt index e69de29bb..ee28c3c1c 100644 --- a/module/error.txt +++ b/module/error.txt @@ -0,0 +1,23 @@ +==== + The MIT License + Copyright (c) 2014 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. +==== + diff --git a/module/etc/module.urm.puml b/module/etc/module.urm.puml index d78f12da8..233691cf7 100644 --- a/module/etc/module.urm.puml +++ b/module/etc/module.urm.puml @@ -16,7 +16,7 @@ package com.iluwatar.module { - singleton : ConsoleLoggerModule {static} - ConsoleLoggerModule() + getSingleton() : ConsoleLoggerModule {static} - + prepare() + + prepare() : ConsoleLoggerModule + printErrorString(value : String) + printString(value : String) + unprepare() @@ -30,7 +30,7 @@ package com.iluwatar.module { - singleton : FileLoggerModule {static} - FileLoggerModule() + getSingleton() : FileLoggerModule {static} - + prepare() + + prepare() : FileLoggerModule + printErrorString(value : String) + printString(value : String) + unprepare() diff --git a/module/output.txt b/module/output.txt index e69de29bb..ee28c3c1c 100644 --- a/module/output.txt +++ b/module/output.txt @@ -0,0 +1,23 @@ +==== + The MIT License + Copyright (c) 2014 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. +==== + diff --git a/object-mother/etc/object-mother.urm.puml b/object-mother/etc/object-mother.urm.puml index 9b26450f0..1bb52f2ed 100644 --- a/object-mother/etc/object-mother.urm.puml +++ b/object-mother/etc/object-mother.urm.puml @@ -1,13 +1,15 @@ @startuml package com.iluwatar.objectmother { - class RoyaltyObjectMother { - + RoyaltyObjectMother() - + createDrunkKing() : King {static} - + createFlirtyQueen() : Queen {static} - + createHappyDrunkKing() : King {static} - + createHappyKing() : King {static} - + createNotFlirtyQueen() : Queen {static} - + createSoberUnhappyKing() : King {static} + class King { + ~ isDrunk : boolean + ~ isHappy : boolean + + King() + + flirt(queen : Queen) + + isHappy() : boolean + + makeDrunk() + + makeHappy() + + makeSober() + + makeUnhappy() } class Queen { - isDrunk : boolean @@ -28,18 +30,16 @@ package com.iluwatar.objectmother { + makeSober() {abstract} + makeUnhappy() {abstract} } - class King { - ~ isDrunk : boolean - ~ isHappy : boolean - + King() - + flirt(queen : Queen) - + isHappy() : boolean - + makeDrunk() - + makeHappy() - + makeSober() - + makeUnhappy() + class RoyaltyObjectMother { + + RoyaltyObjectMother() + + createDrunkKing() : King {static} + + createFlirtyQueen() : Queen {static} + + createHappyDrunkKing() : King {static} + + createHappyKing() : King {static} + + createNotFlirtyQueen() : Queen {static} + + createSoberUnhappyKing() : King {static} } } -Queen ..|> Royalty King ..|> Royalty +Queen ..|> Royalty @enduml \ No newline at end of file diff --git a/object-pool/etc/object-pool.urm.puml b/object-pool/etc/object-pool.urm.puml index 21ef76e0d..ca74f8cec 100644 --- a/object-pool/etc/object-pool.urm.puml +++ b/object-pool/etc/object-pool.urm.puml @@ -6,8 +6,8 @@ package com.iluwatar.object.pool { + main(args : String[]) {static} } abstract class ObjectPool { - - available : HashSet - - inUse : HashSet + - available : Set + - inUse : Set + ObjectPool() + checkIn(instance : T) + checkOut() : T diff --git a/poison-pill/etc/poison-pill.urm.puml b/poison-pill/etc/poison-pill.urm.puml index 923449e10..5c2b9fa2b 100644 --- a/poison-pill/etc/poison-pill.urm.puml +++ b/poison-pill/etc/poison-pill.urm.puml @@ -60,8 +60,8 @@ package com.iluwatar.poison.pill { } } SimpleMessageQueue --> "-queue" Message -Headers ..+ Message Consumer --> "-queue" MqSubscribePoint +Headers ..+ Message Producer --> "-queue" MqPublishPoint Message --> "-POISON_PILL" Message MessageQueue --|> MqPublishPoint diff --git a/promise/etc/promise.urm.puml b/promise/etc/promise.urm.puml index 9c6d09cde..45cae7ff1 100644 --- a/promise/etc/promise.urm.puml +++ b/promise/etc/promise.urm.puml @@ -72,7 +72,7 @@ package com.iluwatar.promise { } TransformAction --> "-src" Promise TransformAction --+ Promise -ConsumeAction --> "-src" Promise ConsumeAction --+ Promise +ConsumeAction --> "-src" Promise Promise --|> PromiseSupport @enduml \ No newline at end of file diff --git a/proxy/etc/presentation.html b/proxy/etc/presentation.html index 7964ae124..f669bf4e9 100644 --- a/proxy/etc/presentation.html +++ b/proxy/etc/presentation.html @@ -1,3 +1,27 @@ + diff --git a/proxy/etc/proxy-concept.xml b/proxy/etc/proxy-concept.xml index c418c8b36..83373a929 100644 --- a/proxy/etc/proxy-concept.xml +++ b/proxy/etc/proxy-concept.xml @@ -1 +1,25 @@ + 7Vhtb5swEP41kbYPnQJuaPexeVv3YVK1aur60YEL8WowM05K+utnYxswkC6p2rSbmkoNfnx3vpfnLsAATZLiC8fZ6huLgA78YVQM0HTg+x4KPPmlkK1GziwQcxIZoRq4Jg9gwKFB1ySC3BEUjFFBMhcMWZpCKBwMc87uXbElo+6pGY6hA1yHmHbRGxKJlUbPR8MavwQSr+zJ3tDsLHB4F3O2Ts15Ax8ty4/eTrC1ZeTzFY7YfQNCswGacMaEvkqKCVCVW5s2rTffsVv5zSEV+yica4UNpmuwHgdUqo4z5Z3YmowEv9fKpXGCeUzSAbqQu8OskP8lWAam8BPBMr132tgTUIgTTEls9ELpG/DapryKzXd5MmkAOJEGx7S7+qpsLHEIFeyqOBZl/KR9yoJ3EAtcrxe/FKtq7UVbVmJZG1txlTLLZRudtzvQJ6WYwlI0crzLdje8PpdfxgMlW9b4ww15wDz6qKU3TLJuT/d8xzF/A1wQ2Z4XmkXTkmdjw6mpdmjMpNSSlt20JJLlaLxkqTDDxfPNeo4TQtVYugS6AWVVlU4kVAkpGak6YZTx8mTbvWicC87uoLEzLD+KahxHRMbb2Juezrz5qIpEuQ/Fzhb1qsaXAxVYAoJvpYhR8M/NrDCz1A6h+3owVeNk5Q4lMxDNMIwr0/VAkBdmJvTPB+vumxoQVTd+B0yP1awR2fQGbFOuHPcf68g8w+lBPSLddnUquPTl9VvlhYmPfJf4fcz3TnuYHzwH8f23TPwrzortO+X/O8oHnkv5s9ERGY/eIuN336VNqCrE/k3wj99SzAL19zw0G70iy7pPHLNCQBrlnQpJ8EI9y8nVgrLwTsYuIZv8QC/nZVmmQzfjMg98+1Phn0Z2eWv3CiIaW3J1awxoDyDqPBu28iq9ZGsegnuLJCTtQTQeq7rpbybYJpMDxYJs3CP7MmzMXTGiWL+jlAi1aqQ9NUrNB8GWHd/7iyEdXsdQWe8qxP0o8PmoFPCaBKiL/tOoVAQodw5v1SeSxn8nzUGkQd37sR85PEYYlkHq8kXN6wjnK4gMLZp0MZTwOpSoZ0mXSE8sPnov/mHF77s12V35lKVQ9izmomd8NOZFKWLWbULs8RPSJcvz/YToEI/CiKD1hqF643AsSsgi4W1DLFMC+eEO1wzTFvfkm1zWb1y1eP1aG83+AA== \ 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 index c0302cd6d..b71cf73f6 100644 --- a/reader-writer-lock/etc/reader-writer-lock.urm.puml +++ b/reader-writer-lock/etc/reader-writer-lock.urm.puml @@ -56,6 +56,6 @@ package com.iluwatar.reader.writer.lock { } ReaderWriterLock --> "-readerLock" ReadLock ReadLock --+ ReaderWriterLock -ReaderWriterLock --> "-writerLock" WriteLock WriteLock --+ ReaderWriterLock +ReaderWriterLock --> "-writerLock" WriteLock @enduml \ No newline at end of file diff --git a/semaphore/etc/semaphore.urm.puml b/semaphore/etc/semaphore.urm.puml index c40f4e026..168fd17e7 100644 --- a/semaphore/etc/semaphore.urm.puml +++ b/semaphore/etc/semaphore.urm.puml @@ -18,7 +18,7 @@ package com.iluwatar.semaphore { + values() : FruitType[] {static} } class FruitBowl { - - fruit : ArrayList + - fruit : List + FruitBowl() + countFruit() : int + put(f : Fruit) @@ -48,8 +48,8 @@ package com.iluwatar.semaphore { + release() } } -Fruit --> "-type" FruitType FruitType ..+ Fruit +Fruit --> "-type" FruitType FruitShop --> "-semaphore" Semaphore FruitBowl --> "-fruit" Fruit Semaphore ..|> Lock diff --git a/state/etc/state.urm.puml b/state/etc/state.urm.puml index ea9a6383a..207a227d8 100644 --- a/state/etc/state.urm.puml +++ b/state/etc/state.urm.puml @@ -31,8 +31,8 @@ package com.iluwatar.state { + onEnterState() {abstract} } } -AngryState --> "-mammoth" Mammoth PeacefulState --> "-mammoth" Mammoth +AngryState --> "-mammoth" Mammoth Mammoth --> "-state" State AngryState ..|> State PeacefulState ..|> State diff --git a/step-builder/etc/step-builder.urm.puml b/step-builder/etc/step-builder.urm.puml index 09fdd05ec..dc6087340 100644 --- a/step-builder/etc/step-builder.urm.puml +++ b/step-builder/etc/step-builder.urm.puml @@ -76,10 +76,10 @@ package com.iluwatar.stepbuilder { } } WeaponStep ..+ CharacterStepBuilder -SpellStep ..+ CharacterStepBuilder CharacterSteps ..+ CharacterStepBuilder -ClassStep ..+ CharacterStepBuilder AbilityStep ..+ CharacterStepBuilder +SpellStep ..+ CharacterStepBuilder +ClassStep ..+ CharacterStepBuilder NameStep ..+ CharacterStepBuilder BuildStep ..+ CharacterStepBuilder CharacterSteps ..|> NameStep From cca4760f6990886c0dd47dea93a6c0d359917073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 12 Feb 2017 00:33:30 +0200 Subject: [PATCH 181/492] #190 Rename package for Queue-Based Load Leveling pattern --- .../etc/queue-load-leveling.urm.puml | 42 +++++++++++++++++++ .../iluwatar}/queue/load/leveling/App.java | 2 +- .../queue/load/leveling/Message.java | 2 +- .../queue/load/leveling/MessageQueue.java | 2 +- .../queue/load/leveling/ServiceExecutor.java | 2 +- .../iluwatar}/queue/load/leveling/Task.java | 2 +- .../queue/load/leveling/TaskGenerator.java | 2 +- .../queue/load/leveling/AppTest.java | 2 +- .../queue/load/leveling/MessageQueueTest.java | 2 +- .../queue/load/leveling/MessageTest.java | 2 +- .../load/leveling/TaskGenSrvExeTest.java | 2 +- 11 files changed, 52 insertions(+), 10 deletions(-) rename queue-load-leveling/src/main/java/{org => com/iluwatar}/queue/load/leveling/App.java (99%) rename queue-load-leveling/src/main/java/{org => com/iluwatar}/queue/load/leveling/Message.java (97%) rename queue-load-leveling/src/main/java/{org => com/iluwatar}/queue/load/leveling/MessageQueue.java (98%) rename queue-load-leveling/src/main/java/{org => com/iluwatar}/queue/load/leveling/ServiceExecutor.java (98%) rename queue-load-leveling/src/main/java/{org => com/iluwatar}/queue/load/leveling/Task.java (96%) rename queue-load-leveling/src/main/java/{org => com/iluwatar}/queue/load/leveling/TaskGenerator.java (98%) rename queue-load-leveling/src/test/java/{org => com/iluwatar}/queue/load/leveling/AppTest.java (96%) rename queue-load-leveling/src/test/java/{org => com/iluwatar}/queue/load/leveling/MessageQueueTest.java (97%) rename queue-load-leveling/src/test/java/{org => com/iluwatar}/queue/load/leveling/MessageTest.java (97%) rename queue-load-leveling/src/test/java/{org => com/iluwatar}/queue/load/leveling/TaskGenSrvExeTest.java (97%) diff --git a/queue-load-leveling/etc/queue-load-leveling.urm.puml b/queue-load-leveling/etc/queue-load-leveling.urm.puml index 02af47ddf..ca90842d9 100644 --- a/queue-load-leveling/etc/queue-load-leveling.urm.puml +++ b/queue-load-leveling/etc/queue-load-leveling.urm.puml @@ -1,2 +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/queue-load-leveling/src/main/java/org/queue/load/leveling/App.java b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/App.java similarity index 99% rename from queue-load-leveling/src/main/java/org/queue/load/leveling/App.java rename to queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/App.java index 19f8939a4..f71d30c16 100644 --- a/queue-load-leveling/src/main/java/org/queue/load/leveling/App.java +++ b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/App.java @@ -21,7 +21,7 @@ * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; diff --git a/queue-load-leveling/src/main/java/org/queue/load/leveling/Message.java b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/Message.java similarity index 97% rename from queue-load-leveling/src/main/java/org/queue/load/leveling/Message.java rename to queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/Message.java index 1f4aa8249..fc218c875 100644 --- a/queue-load-leveling/src/main/java/org/queue/load/leveling/Message.java +++ b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/Message.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; /** * Message class with only one parameter. diff --git a/queue-load-leveling/src/main/java/org/queue/load/leveling/MessageQueue.java b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/MessageQueue.java similarity index 98% rename from queue-load-leveling/src/main/java/org/queue/load/leveling/MessageQueue.java rename to queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/MessageQueue.java index 797226e0a..c1e6d4c28 100644 --- a/queue-load-leveling/src/main/java/org/queue/load/leveling/MessageQueue.java +++ b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/MessageQueue.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; diff --git a/queue-load-leveling/src/main/java/org/queue/load/leveling/ServiceExecutor.java b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/ServiceExecutor.java similarity index 98% rename from queue-load-leveling/src/main/java/org/queue/load/leveling/ServiceExecutor.java rename to queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/ServiceExecutor.java index 02eb43b89..63dbec69f 100644 --- a/queue-load-leveling/src/main/java/org/queue/load/leveling/ServiceExecutor.java +++ b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/ServiceExecutor.java @@ -21,7 +21,7 @@ * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/queue-load-leveling/src/main/java/org/queue/load/leveling/Task.java b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/Task.java similarity index 96% rename from queue-load-leveling/src/main/java/org/queue/load/leveling/Task.java rename to queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/Task.java index 8796f5aae..f85f7d49c 100644 --- a/queue-load-leveling/src/main/java/org/queue/load/leveling/Task.java +++ b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/Task.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; /** * Task Interface. * diff --git a/queue-load-leveling/src/main/java/org/queue/load/leveling/TaskGenerator.java b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/TaskGenerator.java similarity index 98% rename from queue-load-leveling/src/main/java/org/queue/load/leveling/TaskGenerator.java rename to queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/TaskGenerator.java index 211354e53..e99e918db 100644 --- a/queue-load-leveling/src/main/java/org/queue/load/leveling/TaskGenerator.java +++ b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/TaskGenerator.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/queue-load-leveling/src/test/java/org/queue/load/leveling/AppTest.java b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/AppTest.java similarity index 96% rename from queue-load-leveling/src/test/java/org/queue/load/leveling/AppTest.java rename to queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/AppTest.java index dbf0c1269..d1cf75ca8 100644 --- a/queue-load-leveling/src/test/java/org/queue/load/leveling/AppTest.java +++ b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/AppTest.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import java.io.IOException; diff --git a/queue-load-leveling/src/test/java/org/queue/load/leveling/MessageQueueTest.java b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/MessageQueueTest.java similarity index 97% rename from queue-load-leveling/src/test/java/org/queue/load/leveling/MessageQueueTest.java rename to queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/MessageQueueTest.java index 2b2110a56..30b5d7ce0 100644 --- a/queue-load-leveling/src/test/java/org/queue/load/leveling/MessageQueueTest.java +++ b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/MessageQueueTest.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import static org.junit.Assert.assertEquals; diff --git a/queue-load-leveling/src/test/java/org/queue/load/leveling/MessageTest.java b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/MessageTest.java similarity index 97% rename from queue-load-leveling/src/test/java/org/queue/load/leveling/MessageTest.java rename to queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/MessageTest.java index 72a0b7406..93ef723ea 100644 --- a/queue-load-leveling/src/test/java/org/queue/load/leveling/MessageTest.java +++ b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/MessageTest.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/queue-load-leveling/src/test/java/org/queue/load/leveling/TaskGenSrvExeTest.java b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/TaskGenSrvExeTest.java similarity index 97% rename from queue-load-leveling/src/test/java/org/queue/load/leveling/TaskGenSrvExeTest.java rename to queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/TaskGenSrvExeTest.java index d98fee30a..a773c377e 100644 --- a/queue-load-leveling/src/test/java/org/queue/load/leveling/TaskGenSrvExeTest.java +++ b/queue-load-leveling/src/test/java/com/iluwatar/queue/load/leveling/TaskGenSrvExeTest.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.queue.load.leveling; +package com.iluwatar.queue.load.leveling; import org.junit.Test; From fd7107694a75ebe7cadee666e3d397ed468df86f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Feb 2017 15:16:15 +0100 Subject: [PATCH 182/492] Update pom.xml Changed 1.14.0-SNAPSHOT to 1.15.0-SNAPSHOT --- tls/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tls/pom.xml b/tls/pom.xml index 68ebcdbf1..fa8bf6860 100644 --- a/tls/pom.xml +++ b/tls/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT tls From eecffb0ea5deba13fd73b17dfacb2aca2b5d28e4 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Fri, 3 Mar 2017 19:58:03 +0000 Subject: [PATCH 183/492] #467 data-bus: add stub --- data-bus/.gitignore | 1 + data-bus/pom.xml | 64 +++++++++++++++++++++++++++++++++++++++++++++ pom.xml | 1 + 3 files changed, 66 insertions(+) create mode 100644 data-bus/.gitignore create mode 100644 data-bus/pom.xml diff --git a/data-bus/.gitignore b/data-bus/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/data-bus/.gitignore @@ -0,0 +1 @@ +/target diff --git a/data-bus/pom.xml b/data-bus/pom.xml new file mode 100644 index 000000000..01f5649ab --- /dev/null +++ b/data-bus/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + 1.16.14 + + + com.iluwatar + java-design-patterns + 1.15.0-SNAPSHOT + + data-bus + + + junit + junit + test + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19 + + false + + + + + diff --git a/pom.xml b/pom.xml index 5ddd3bf98..08477db20 100644 --- a/pom.xml +++ b/pom.xml @@ -134,6 +134,7 @@ event-asynchronous queue-load-leveling object-mother + data-bus From 3fd68879755aca69e5f1f1cbf64618ffbf7be5ab Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 5 Mar 2017 12:15:59 +0000 Subject: [PATCH 184/492] #467 data-bus: implement pattern --- data-bus/README.md | 30 ++++++++ .../iluwatar/databus/AbstractDataType.java | 45 ++++++++++++ .../main/java/com/iluwatar/databus/App.java | 60 +++++++++++++++ .../java/com/iluwatar/databus/DataBus.java | 73 +++++++++++++++++++ .../java/com/iluwatar/databus/DataType.java | 48 ++++++++++++ .../java/com/iluwatar/databus/Member.java | 37 ++++++++++ .../iluwatar/databus/data/MessageData.java | 47 ++++++++++++ .../iluwatar/databus/data/StartingData.java | 49 +++++++++++++ .../iluwatar/databus/data/StoppingData.java | 49 +++++++++++++ .../databus/members/CounterMember.java | 53 ++++++++++++++ .../databus/members/StatusMember.java | 63 ++++++++++++++++ pom.xml | 2 +- 12 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 data-bus/README.md create mode 100644 data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/App.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/DataBus.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/DataType.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/Member.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java create mode 100644 data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java diff --git a/data-bus/README.md b/data-bus/README.md new file mode 100644 index 000000000..675e9fa3c --- /dev/null +++ b/data-bus/README.md @@ -0,0 +1,30 @@ +--- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/ +layout: pattern # layout must allways be pattern +title: Data Bus # the properly formatted title +folder: data-bus # the folder name in which this pattern lies +permalink: /patterns/data-bus/ # the permalink to the pattern, to keep this uniform please stick to /patterns/FOLDER/ + +# both categories and tags are Yaml Lists +# you can either just pick one or write a list with '-'s +# usable categories and tags are listed here: https://github.com/iluwatar/java-design-patterns/blob/gh-pages/_config.yml +categories: creational # categories of the pattern +tags: # tags of the pattern + - best + - ever + - awesome +--- + +## Intent +Makes your code awesome + +![alt text](./etc/best_pattern.png "Best Pattern Ever") + +## Applicability +Use the Best Pattern Ever pattern when + +* you want to be the best +* you need to ... + +## Real world examples + +* [Nowhere](http://no.where.com) diff --git a/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java b/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java new file mode 100644 index 000000000..8926ce9aa --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java @@ -0,0 +1,45 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Paul Campbell + +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.databus; + +/** + * . + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +public class AbstractDataType implements DataType { + + private DataBus dataBus; + + @Override + public DataBus getDataBus() { + return dataBus; + } + + @Override + public void setDataBus(DataBus dataBus) { + this.dataBus = dataBus; + } +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/App.java b/data-bus/src/main/java/com/iluwatar/databus/App.java new file mode 100644 index 000000000..b76873cec --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/App.java @@ -0,0 +1,60 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.databus; + +import com.iluwatar.databus.data.StoppingData; +import com.iluwatar.databus.data.StartingData; +import com.iluwatar.databus.data.MessageData; +import com.iluwatar.databus.members.CounterMember; +import com.iluwatar.databus.members.StatusMember; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; + +/** + * The Data Bus pattern + *

    + *

    {@see http://wiki.c2.com/?DataBusPattern}

    + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +@Slf4j +class App { + + public static void main(String[] args) { + final DataBus bus = DataBus.getInstance(); + bus.subscribe(new StatusMember(1)); + bus.subscribe(new StatusMember(2)); + final CounterMember foo = new CounterMember("Foo"); + final CounterMember bar = new CounterMember("Bar"); + bus.subscribe(foo); + bus.publish(StartingData.of(LocalDateTime.now())); + bus.publish(MessageData.of("Only Foo should see this")); + bus.subscribe(bar); + bus.publish(MessageData.of("Foo and Bar should see this")); + bus.unsubscribe(foo); + bus.publish(MessageData.of("Only Bar should see this")); + bus.publish(StoppingData.of(LocalDateTime.now())); + } +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/DataBus.java b/data-bus/src/main/java/com/iluwatar/databus/DataBus.java new file mode 100644 index 000000000..edaefe623 --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/DataBus.java @@ -0,0 +1,73 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.databus; + +import java.util.HashSet; +import java.util.Set; + +/** + * The Data-Bus implementation. + * + *

    This implementation uses a Singleton.

    + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +public class DataBus { + + private static final DataBus INSTANCE = new DataBus(); + + private final Set listeners = new HashSet<>(); + + public static DataBus getInstance() { + return INSTANCE; + } + + /** + * Register a member with the data-bus to start receiving events. + * + * @param member The member to register + */ + public void subscribe(final Member member) { + this.listeners.add(member); + } + + /** + * Deregister a member to stop receiving events. + * + * @param member The member to deregister + */ + public void unsubscribe(final Member member) { + this.listeners.remove(member); + } + + /** + * Publish and event to all members. + * + * @param event The event + */ + public void publish(final DataType event) { + event.setDataBus(this); + listeners.forEach(listener -> listener.accept(event)); + } +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/DataType.java b/data-bus/src/main/java/com/iluwatar/databus/DataType.java new file mode 100644 index 000000000..e5729c19d --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/DataType.java @@ -0,0 +1,48 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Paul Campbell + +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.databus; + +/** + * Events are sent via the Data-Bus. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ + +public interface DataType { + + /** + * Returns the data-bus the event is being sent on. + * + * @return The data-bus + */ + DataBus getDataBus(); + + /** + * Set the data-bus the event will be sent on. + * + * @param dataBus The data-bus + */ + void setDataBus(DataBus dataBus); +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/Member.java b/data-bus/src/main/java/com/iluwatar/databus/Member.java new file mode 100644 index 000000000..d5ecb0152 --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/Member.java @@ -0,0 +1,37 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Paul Campbell + +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.databus; + +import java.util.function.Consumer; + +/** + * Members receive events from the Data-Bus. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +public interface Member extends Consumer { + + void accept(DataType event); +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java b/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java new file mode 100644 index 000000000..2750b013e --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.databus.data; + +import com.iluwatar.databus.AbstractDataType; +import com.iluwatar.databus.DataType; +import lombok.RequiredArgsConstructor; + +/** + * . + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +@RequiredArgsConstructor +public class MessageData extends AbstractDataType { + + private final String message; + + public String getMessage() { + return message; + } + + public static DataType of(final String message) { + return new MessageData(message); + } +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java b/data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java new file mode 100644 index 000000000..f7159b77a --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.databus.data; + +import com.iluwatar.databus.AbstractDataType; +import com.iluwatar.databus.DataType; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; + +/** + * An event raised when applications starts, containing the start time of the application. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +@RequiredArgsConstructor +public class StartingData extends AbstractDataType { + + private final LocalDateTime when; + + public LocalDateTime getWhen() { + return when; + } + + public static DataType of(final LocalDateTime when) { + return new StartingData(when); + } +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java b/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java new file mode 100644 index 000000000..57918ec4c --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.databus.data; + +import com.iluwatar.databus.AbstractDataType; +import com.iluwatar.databus.DataType; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; + +/** + * . + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +@RequiredArgsConstructor +public class StoppingData extends AbstractDataType { + + private final LocalDateTime when; + + public LocalDateTime getWhen() { + return when; + } + + public static DataType of(final LocalDateTime when) { + return new StoppingData(when); + } +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java b/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java new file mode 100644 index 000000000..45c90abb0 --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.databus.members; + +import com.iluwatar.databus.DataType; +import com.iluwatar.databus.Member; +import com.iluwatar.databus.data.MessageData; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Receiver of Data-Bus events. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +@Slf4j +@RequiredArgsConstructor +public class CounterMember implements Member { + + private final String name; + + @Override + public void accept(final DataType data) { + if (data instanceof MessageData) { + handleEvent((MessageData) data); + } + } + + private void handleEvent(MessageData data) { + log.info("{} sees message {}", name, data.getMessage()); + } +} diff --git a/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java b/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java new file mode 100644 index 000000000..5e1ca1656 --- /dev/null +++ b/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java @@ -0,0 +1,63 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.databus.members; + +import com.iluwatar.databus.DataType; +import com.iluwatar.databus.Member; +import com.iluwatar.databus.data.MessageData; +import com.iluwatar.databus.data.StartingData; +import com.iluwatar.databus.data.StoppingData; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Receiver of Data-Bus events. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +@Slf4j +@RequiredArgsConstructor +public class StatusMember implements Member { + + private final int id; + + @Override + public void accept(final DataType data) { + if (data instanceof StartingData) { + handleEvent((StartingData) data); + } else if (data instanceof StoppingData) { + handleEvent((StoppingData) data); + } + } + + private void handleEvent(StartingData data) { + log.info("Receiver #{} sees application started at {}", id, data.getWhen()); + } + + private void handleEvent(StoppingData data) { + log.info("Receiver #{} sees application stopping at {}", id, data.getWhen()); + log.info("Receiver #{} sending goodbye message", id); + data.getDataBus().publish(MessageData.of(String.format("Goodbye cruel world from #%d!", id))); + } +} diff --git a/pom.xml b/pom.xml index 08477db20..4a474d091 100644 --- a/pom.xml +++ b/pom.xml @@ -467,4 +467,4 @@ - \ No newline at end of file + From b5bdf2d7d708626b3957ebba9950f7e71035d06f Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 5 Mar 2017 19:43:26 +0000 Subject: [PATCH 185/492] #467 data-bus: etc: add urm diagrams --- data-bus/etc/data-bus.urm.png | Bin 0 -> 61121 bytes data-bus/etc/data-bus.urm.puml | 77 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 data-bus/etc/data-bus.urm.png create mode 100644 data-bus/etc/data-bus.urm.puml diff --git a/data-bus/etc/data-bus.urm.png b/data-bus/etc/data-bus.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..8bd2148174e4ce0cca85051d0c67a004e6d1e5fd GIT binary patch literal 61121 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%0A8B(lGa>!X0%#dOQ+z&% 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 H^VR + + DataBus() + + getInstance() : DataBus {static} + + publish(event : DataType) + + subscribe(member : Member) + + unsubscribe(member : Member) + } + interface DataType { + + getDataBus() : DataBus {abstract} + + setDataBus(DataBus) {abstract} + } + interface Member { + + accept(DataType) {abstract} + } +} +package com.iluwatar.databus.data { + class MessageData { + - message : String + + MessageData(message : String) + + getMessage() : String + + of(message : String) : DataType {static} + } + class StartingData { + - when : LocalDateTime + + StartingData(when : LocalDateTime) + + getWhen() : LocalDateTime + + of(when : LocalDateTime) : DataType {static} + } + class StoppingData { + - when : LocalDateTime + + StoppingData(when : LocalDateTime) + + getWhen() : LocalDateTime + + of(when : LocalDateTime) : DataType {static} + } +} +package com.iluwatar.databus.members { + class CounterMember { + - log : Logger {static} + - name : String + + CounterMember(name : String) + + accept(data : DataType) + - handleEvent(data : MessageData) + } + class StatusMember { + - id : int + - log : Logger {static} + + StatusMember(id : int) + + accept(data : DataType) + - handleEvent(data : StartingData) + - handleEvent(data : StoppingData) + } +} +AbstractDataType --> "-dataBus" DataBus +DataBus --> "-INSTANCE" DataBus +DataBus --> "-listeners" Member +AbstractDataType ..|> DataType +MessageData --|> AbstractDataType +StartingData --|> AbstractDataType +StoppingData --|> AbstractDataType +CounterMember ..|> Member +StatusMember ..|> Member +@enduml \ No newline at end of file From 6b795e52c324d00cec4a281753b4ef514b040a14 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 5 Mar 2017 19:43:57 +0000 Subject: [PATCH 186/492] #467 data-bus: README.md: updated for data-bus --- data-bus/README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/data-bus/README.md b/data-bus/README.md index 675e9fa3c..d65af8732 100644 --- a/data-bus/README.md +++ b/data-bus/README.md @@ -7,24 +7,30 @@ permalink: /patterns/data-bus/ # the permalink to the pattern, to keep this unif # both categories and tags are Yaml Lists # you can either just pick one or write a list with '-'s # usable categories and tags are listed here: https://github.com/iluwatar/java-design-patterns/blob/gh-pages/_config.yml -categories: creational # categories of the pattern +categories: Architectural # categories of the pattern tags: # tags of the pattern - - best - - ever - - awesome + - Java + - Difficulty-Intermediate --- ## Intent -Makes your code awesome -![alt text](./etc/best_pattern.png "Best Pattern Ever") +Allows send of messages/events between components of an application +without them needing to know about each other. They only need to know +about the type of the message/event being sent. + +![data bus pattern uml diagram](./etc/data-bus.urm.png "Data Bus pattern") ## Applicability -Use the Best Pattern Ever pattern when +Use Data Bus pattern when -* you want to be the best -* you need to ... +* you want your components to decide themselves which messages/events they want to receive +* you want to have many-to-many communication +* you want your components to know nothing about each other -## Real world examples +## Related Patterns +Data Bus is similar to -* [Nowhere](http://no.where.com) +* Mediator pattern with Data Bus Members deciding for themselves if they want to accept any given message +* Observer pattern but supporting many-to-many communication +* Publish/Subscribe pattern with the Data Bus decoupling the publisher and the subscriber From 8871f788d2564ff383e5527a6db45aa5b3edcc79 Mon Sep 17 00:00:00 2001 From: Kamil Pietruszka Date: Fri, 10 Mar 2017 20:08:58 +0100 Subject: [PATCH 187/492] #497 Converter pattern implementation --- converter/README.md | 25 ++++++ converter/pom.xml | 21 +++++ .../main/java/com/iluwatar/converter/App.java | 44 ++++++++++ .../com/iluwatar/converter/Converter.java | 86 +++++++++++++++++++ .../java/com/iluwatar/converter/User.java | 69 +++++++++++++++ .../java/com/iluwatar/converter/UserDto.java | 69 +++++++++++++++ .../java/com/iluwatar/converter/AppTest.java | 35 ++++++++ pom.xml | 3 +- 8 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 converter/README.md create mode 100644 converter/pom.xml create mode 100644 converter/src/main/java/com/iluwatar/converter/App.java create mode 100644 converter/src/main/java/com/iluwatar/converter/Converter.java create mode 100644 converter/src/main/java/com/iluwatar/converter/User.java create mode 100644 converter/src/main/java/com/iluwatar/converter/UserDto.java create mode 100644 converter/src/test/java/com/iluwatar/converter/AppTest.java diff --git a/converter/README.md b/converter/README.md new file mode 100644 index 000000000..cbca98e8f --- /dev/null +++ b/converter/README.md @@ -0,0 +1,25 @@ +--- +layout: pattern +title: Converter +folder: converter +permalink: /patterns/converter/ +categories: +tags: + - Java + - Difficulty-Beginner +--- + +## Intent +TODO + +![alt text](./etc/converter.png "TODO") + +## Applicability +TODO + +* TODO 1 +* TODO 2 + +## Credits + +* [Converter](http://todo.com) diff --git a/converter/pom.xml b/converter/pom.xml new file mode 100644 index 000000000..53eca720b --- /dev/null +++ b/converter/pom.xml @@ -0,0 +1,21 @@ + + + + java-design-patterns + com.iluwatar + 1.15.0-SNAPSHOT + + 4.0.0 + + + junit + junit + test + + + converter + + + diff --git a/converter/src/main/java/com/iluwatar/converter/App.java b/converter/src/main/java/com/iluwatar/converter/App.java new file mode 100644 index 000000000..593240b43 --- /dev/null +++ b/converter/src/main/java/com/iluwatar/converter/App.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.converter; + +/** + * + * + */ +public class App { + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { + Converter userConverter = new Converter<>( + userDto -> new User(userDto.getName(), userDto.getSurname(), userDto.isActive()), + user -> new UserDto(user.getName(), user.getSurname(), user.isActive())); + UserDto dtoUser = new UserDto("John", "Doe", true); + User user = userConverter.convertFromDTO(dtoUser); + UserDto dtoUserCopy = userConverter.convertFromEntity(user); + + } +} diff --git a/converter/src/main/java/com/iluwatar/converter/Converter.java b/converter/src/main/java/com/iluwatar/converter/Converter.java new file mode 100644 index 000000000..0b3531a22 --- /dev/null +++ b/converter/src/main/java/com/iluwatar/converter/Converter.java @@ -0,0 +1,86 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.converter; + +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @param + * @param + */ +public class Converter { + /** + * + */ + private final Function fromDTO; + /** + * + */ + private final Function fromEntity; + + /** + * @param fromDTO + * @param fromEntity + */ + public Converter(final Function fromDTO, final Function fromEntity) { + this.fromDTO = fromDTO; + this.fromEntity = fromEntity; + } + + /** + * @param arg + * @return + */ + public U convertFromDTO(final T arg) { + return fromDTO.apply(arg); + } + + /** + * @param arg + * @return + */ + public T convertFromEntity(final U arg) { + return fromEntity.apply(arg); + } + + /** + * @param arg + * @return + */ + public List createFromDTOs(final Collection arg) { + return arg.stream().map(this::convertFromDTO).collect(Collectors.toList()); + } + + /** + * @param arg + * @return + */ + public List createFromEntities(final Collection arg) { + return arg.stream().map(this::convertFromEntity).collect(Collectors.toList()); + } + +} diff --git a/converter/src/main/java/com/iluwatar/converter/User.java b/converter/src/main/java/com/iluwatar/converter/User.java new file mode 100644 index 000000000..bcd09c1cc --- /dev/null +++ b/converter/src/main/java/com/iluwatar/converter/User.java @@ -0,0 +1,69 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.converter; + +/** + * Created by crossy on 2017-03-10. + */ +public class User { + private String name; + private String surname; + private boolean isActive; + + /** + * + * @param name + * @param surname + * @param isActive + */ + public User(String name, String surname, boolean isActive) { + this.name = name; + this.surname = surname; + this.isActive = isActive; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } +} diff --git a/converter/src/main/java/com/iluwatar/converter/UserDto.java b/converter/src/main/java/com/iluwatar/converter/UserDto.java new file mode 100644 index 000000000..aaff1e623 --- /dev/null +++ b/converter/src/main/java/com/iluwatar/converter/UserDto.java @@ -0,0 +1,69 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.converter; + +/** + * + */ +public class UserDto { + private String name; + private String surname; + private boolean isActive; + + /** + * + * @param name + * @param surname + * @param isActive + */ + public UserDto(String name, String surname, boolean isActive) { + this.name = name; + this.surname = surname; + this.isActive = isActive; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } +} diff --git a/converter/src/test/java/com/iluwatar/converter/AppTest.java b/converter/src/test/java/com/iluwatar/converter/AppTest.java new file mode 100644 index 000000000..5198827d2 --- /dev/null +++ b/converter/src/test/java/com/iluwatar/converter/AppTest.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.converter; + +import org.junit.Test; + +public class AppTest { + + @Test + public void testMain() { + String[] args = {}; + App.main(args); + } + +} diff --git a/pom.xml b/pom.xml index 5ddd3bf98..8a012665d 100644 --- a/pom.xml +++ b/pom.xml @@ -134,6 +134,7 @@ event-asynchronous queue-load-leveling object-mother + converter @@ -466,4 +467,4 @@ - \ No newline at end of file + From e8b634c33e03f57af5e87364a55d898a32518216 Mon Sep 17 00:00:00 2001 From: Kamil Pietruszka Date: Fri, 10 Mar 2017 20:59:24 +0100 Subject: [PATCH 188/492] java docs added --- .../main/java/com/iluwatar/converter/App.java | 10 ++-- .../com/iluwatar/converter/Converter.java | 47 +++++++++---------- .../java/com/iluwatar/converter/User.java | 35 +++++++------- .../java/com/iluwatar/converter/UserDto.java | 36 +++++++------- 4 files changed, 58 insertions(+), 70 deletions(-) diff --git a/converter/src/main/java/com/iluwatar/converter/App.java b/converter/src/main/java/com/iluwatar/converter/App.java index 593240b43..91fbb98f8 100644 --- a/converter/src/main/java/com/iluwatar/converter/App.java +++ b/converter/src/main/java/com/iluwatar/converter/App.java @@ -22,10 +22,6 @@ */ package com.iluwatar.converter; -/** - * - * - */ public class App { /** * Program entry point @@ -34,10 +30,10 @@ public class App { */ public static void main(String[] args) { Converter userConverter = new Converter<>( - userDto -> new User(userDto.getName(), userDto.getSurname(), userDto.isActive()), - user -> new UserDto(user.getName(), user.getSurname(), user.isActive())); + userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive()), + user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive())); UserDto dtoUser = new UserDto("John", "Doe", true); - User user = userConverter.convertFromDTO(dtoUser); + User user = userConverter.convertFromDto(dtoUser); UserDto dtoUserCopy = userConverter.convertFromEntity(user); } diff --git a/converter/src/main/java/com/iluwatar/converter/Converter.java b/converter/src/main/java/com/iluwatar/converter/Converter.java index 0b3531a22..7f7a702cd 100644 --- a/converter/src/main/java/com/iluwatar/converter/Converter.java +++ b/converter/src/main/java/com/iluwatar/converter/Converter.java @@ -29,55 +29,52 @@ import java.util.function.Function; import java.util.stream.Collectors; /** - * @param - * @param + * @param DTO representation's type + * @param Domain representation's type */ public class Converter { - /** - * - */ - private final Function fromDTO; - /** - * - */ + + private final Function fromDto; private final Function fromEntity; /** - * @param fromDTO - * @param fromEntity + * @param fromDto Function that converts given dto entity into the domain entity. + * @param fromEntity Function that converts given domain entity into the dto entity. */ - public Converter(final Function fromDTO, final Function fromEntity) { - this.fromDTO = fromDTO; + public Converter(final Function fromDto, final Function fromEntity) { + this.fromDto = fromDto; this.fromEntity = fromEntity; } /** - * @param arg - * @return + * @param arg DTO entity + * @return The domain representation - the result of the converting function application on dto entity. */ - public U convertFromDTO(final T arg) { - return fromDTO.apply(arg); + public U convertFromDto(final T arg) { + return fromDto.apply(arg); } /** - * @param arg - * @return + * @param arg domain entity + * @return The DTO representation - the result of the converting function application on domain entity. */ public T convertFromEntity(final U arg) { return fromEntity.apply(arg); } /** - * @param arg - * @return + * @param arg collection of DTO entities + * @return List of domain representation of provided entities retrieved by + * mapping each of them with the convertion function */ - public List createFromDTOs(final Collection arg) { - return arg.stream().map(this::convertFromDTO).collect(Collectors.toList()); + public List createFromDtos(final Collection arg) { + return arg.stream().map(this::convertFromDto).collect(Collectors.toList()); } /** - * @param arg - * @return + * @param arg collection of domain entities + * @return List of domain representation of provided entities retrieved by + * mapping each of them with the convertion function */ public List createFromEntities(final Collection arg) { return arg.stream().map(this::convertFromEntity).collect(Collectors.toList()); diff --git a/converter/src/main/java/com/iluwatar/converter/User.java b/converter/src/main/java/com/iluwatar/converter/User.java index bcd09c1cc..8a4e9186c 100644 --- a/converter/src/main/java/com/iluwatar/converter/User.java +++ b/converter/src/main/java/com/iluwatar/converter/User.java @@ -23,40 +23,37 @@ package com.iluwatar.converter; -/** - * Created by crossy on 2017-03-10. - */ public class User { - private String name; - private String surname; + private String firstName; + private String lastName; private boolean isActive; /** * - * @param name - * @param surname - * @param isActive + * @param firstName user's first name + * @param lastName user's last name + * @param isActive flag indicating whether the user is active */ - public User(String name, String surname, boolean isActive) { - this.name = name; - this.surname = surname; + public User(String firstName, String lastName, boolean isActive) { + this.firstName = firstName; + this.lastName = lastName; this.isActive = isActive; } - public String getName() { - return name; + public String getFirstName() { + return firstName; } - public void setName(String name) { - this.name = name; + public void setFirstName(String firstName) { + this.firstName = firstName; } - public String getSurname() { - return surname; + public String getLastName() { + return lastName; } - public void setSurname(String surname) { - this.surname = surname; + public void setLastName(String lastName) { + this.lastName = lastName; } public boolean isActive() { diff --git a/converter/src/main/java/com/iluwatar/converter/UserDto.java b/converter/src/main/java/com/iluwatar/converter/UserDto.java index aaff1e623..bdadf6e39 100644 --- a/converter/src/main/java/com/iluwatar/converter/UserDto.java +++ b/converter/src/main/java/com/iluwatar/converter/UserDto.java @@ -23,40 +23,38 @@ package com.iluwatar.converter; -/** - * - */ + public class UserDto { - private String name; - private String surname; + private String firstName; + private String lastName; private boolean isActive; /** * - * @param name - * @param surname - * @param isActive + * @param firstName user's first name + * @param lastName user's last name + * @param isActive flag indicating whether the user is active */ - public UserDto(String name, String surname, boolean isActive) { - this.name = name; - this.surname = surname; + public UserDto(String firstName, String lastName, boolean isActive) { + this.firstName = firstName; + this.lastName = lastName; this.isActive = isActive; } - public String getName() { - return name; + public String getFirstName() { + return firstName; } - public void setName(String name) { - this.name = name; + public void setFirstName(String firstName) { + this.firstName = firstName; } - public String getSurname() { - return surname; + public String getLastName() { + return lastName; } - public void setSurname(String surname) { - this.surname = surname; + public void setLastName(String lastName) { + this.lastName = lastName; } public boolean isActive() { From 764ff4bf5374e5c09bdd821a82537b2e283c15c3 Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Fri, 6 Jan 2017 00:57:47 +0100 Subject: [PATCH 189/492] Initial commit of guarded suspension design pattern --- guarded-suspension/README.md | 21 ++++++ guarded-suspension/etc/guarded-suspension.png | Bin 0 -> 8011 bytes .../etc/guarded-suspension.ucls | 22 ++++++ .../etc/guarded-suspension.urm.puml | 11 +++ guarded-suspension/pom.xml | 45 ++++++++++++ .../guarded/suspension/GuardedQueue.java | 66 ++++++++++++++++++ .../guarded/suspension/GuardedQueueTest.java | 53 ++++++++++++++ pom.xml | 1 + 8 files changed, 219 insertions(+) create mode 100644 guarded-suspension/README.md create mode 100644 guarded-suspension/etc/guarded-suspension.png create mode 100644 guarded-suspension/etc/guarded-suspension.ucls create mode 100644 guarded-suspension/etc/guarded-suspension.urm.puml create mode 100644 guarded-suspension/pom.xml create mode 100644 guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java create mode 100644 guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java diff --git a/guarded-suspension/README.md b/guarded-suspension/README.md new file mode 100644 index 000000000..df10a9ef3 --- /dev/null +++ b/guarded-suspension/README.md @@ -0,0 +1,21 @@ +--- +layout: pattern +title: Guarded Suspension +folder: guarded-suspension +permalink: /patterns/guarded-suspension/ +pumlid: RScv3SCm3030LU819FRPXg5fIm552tnYPFiyjRi3RkbAaYkdoQr5JBy369vrxz7oaSv6XmPhL3e6TCaJ0msU-CAoilTToyG8DdKOw5z0GzcAlvNAN_WZSD1brBHHPmxv0000 +categories: Concurrency +tags: + - Java + - Difficulty-Beginner +--- + +## Intent +Use Guareded suspension pattern to handle a situation when you want to execute a method on object which is not in a proper state. +![Guarded Suspension diagram](./etc/guarded-suspension.png) + +## Applicability +Use Guareded Suspension pattern when: + +* the developer knows that the method execution will be blocked for a finite period of time + diff --git a/guarded-suspension/etc/guarded-suspension.png b/guarded-suspension/etc/guarded-suspension.png new file mode 100644 index 0000000000000000000000000000000000000000..db962e539b40d41364de4496a41d1e6542f8cfff GIT binary patch literal 8011 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 E0VIn*qW}N^ literal 0 HcmV?d00001 diff --git a/guarded-suspension/etc/guarded-suspension.ucls b/guarded-suspension/etc/guarded-suspension.ucls new file mode 100644 index 000000000..2e46325e4 --- /dev/null +++ b/guarded-suspension/etc/guarded-suspension.ucls @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/guarded-suspension/etc/guarded-suspension.urm.puml b/guarded-suspension/etc/guarded-suspension.urm.puml new file mode 100644 index 000000000..f99607d82 --- /dev/null +++ b/guarded-suspension/etc/guarded-suspension.urm.puml @@ -0,0 +1,11 @@ +@startuml +package com.iluwatar.guarded.suspension { + class GuardedQueue { + - LOGGER : Logger {static} + - sourceList : Queue + + GuardedQueue() + + get() : Integer + + put(e : Integer) + } +} +@enduml \ No newline at end of file diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml new file mode 100644 index 000000000..a7d813ae2 --- /dev/null +++ b/guarded-suspension/pom.xml @@ -0,0 +1,45 @@ + + + + + java-design-patterns + com.iluwatar + 1.14.0-SNAPSHOT + + 4.0.0 + + guarded-suspension + + + junit + junit + + + + + \ No newline at end of file diff --git a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java new file mode 100644 index 000000000..a5b16544f --- /dev/null +++ b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java @@ -0,0 +1,66 @@ +/** + * The MIT License + * Copyright (c) 2014 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.guarded.suspension; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.Queue; + + + +public class GuardedQueue { + private static final Logger LOGGER = LoggerFactory.getLogger(GuardedQueue.class); + private Queue sourceList; + + public GuardedQueue() { + this.sourceList = new LinkedList<>(); + } + + /** + * @return last element of a queue if queue is not empty + */ + public synchronized Integer get() { + while (sourceList.isEmpty()) { + try { + LOGGER.info("waiting"); + wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + return sourceList.peek(); + } + + /** + * @param e number which we want to put to our queue + */ + public synchronized void put(Integer e) { + sourceList.add(e); + notify(); + LOGGER.info("notifying"); + + } +} diff --git a/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java new file mode 100644 index 000000000..ca1ffad28 --- /dev/null +++ b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright (c) 2014 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.guarded.suspension; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Created by robertt240 on 1/2/17. + */ +public class GuardedQueueTest { + private volatile Integer value; + + @Test + public void testGet() { + GuardedQueue g = new GuardedQueue(); + ExecutorService executorService = Executors.newFixedThreadPool(2); + executorService.submit(() -> value = g.get()); + executorService.submit(() -> g.put(Integer.valueOf(10))); + executorService.shutdown(); + try { + executorService.awaitTermination(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Assert.assertEquals(Integer.valueOf(10), value); + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5ddd3bf98..242ae4b1a 100644 --- a/pom.xml +++ b/pom.xml @@ -134,6 +134,7 @@ event-asynchronous queue-load-leveling object-mother + guarded-suspension From 1824b4138b17c972fc0012c5cb91e82938e5ddb4 Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Fri, 6 Jan 2017 01:00:23 +0100 Subject: [PATCH 190/492] readme fix --- guarded-suspension/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/guarded-suspension/README.md b/guarded-suspension/README.md index df10a9ef3..ca6f5886f 100644 --- a/guarded-suspension/README.md +++ b/guarded-suspension/README.md @@ -3,7 +3,6 @@ layout: pattern title: Guarded Suspension folder: guarded-suspension permalink: /patterns/guarded-suspension/ -pumlid: RScv3SCm3030LU819FRPXg5fIm552tnYPFiyjRi3RkbAaYkdoQr5JBy369vrxz7oaSv6XmPhL3e6TCaJ0msU-CAoilTToyG8DdKOw5z0GzcAlvNAN_WZSD1brBHHPmxv0000 categories: Concurrency tags: - Java From a09866d35b146517c6ca02e68992048031b04ba7 Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Fri, 6 Jan 2017 01:01:47 +0100 Subject: [PATCH 191/492] another readme fix --- guarded-suspension/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/guarded-suspension/README.md b/guarded-suspension/README.md index ca6f5886f..01c03f192 100644 --- a/guarded-suspension/README.md +++ b/guarded-suspension/README.md @@ -11,6 +11,7 @@ tags: ## Intent Use Guareded suspension pattern to handle a situation when you want to execute a method on object which is not in a proper state. + ![Guarded Suspension diagram](./etc/guarded-suspension.png) ## Applicability From e5034c6ae99e11684f4dd8d9d5ee74b14a361c4a Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Fri, 6 Jan 2017 01:25:47 +0100 Subject: [PATCH 192/492] guarded suspension pattern #69 --- .../java/com/iluwatar/guarded/suspension/GuardedQueue.java | 7 +++---- .../com/iluwatar/guarded/suspension/GuardedQueueTest.java | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java index a5b16544f..47939141f 100644 --- a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java +++ b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java @@ -1,17 +1,17 @@ /** * The MIT License * Copyright (c) 2014 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 @@ -29,7 +29,6 @@ import java.util.LinkedList; import java.util.Queue; - public class GuardedQueue { private static final Logger LOGGER = LoggerFactory.getLogger(GuardedQueue.class); private Queue sourceList; diff --git a/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java index ca1ffad28..45251acbf 100644 --- a/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java +++ b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java @@ -29,9 +29,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -/** - * Created by robertt240 on 1/2/17. - */ public class GuardedQueueTest { private volatile Integer value; From 29715028d15f2afa442edefa4088cf6c4cf49f71 Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Mon, 9 Jan 2017 21:17:36 +0100 Subject: [PATCH 193/492] fix in POM formatting #69 --- guarded-suspension/pom.xml | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index a7d813ae2..8326a6e96 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -26,20 +26,18 @@ - - java-design-patterns - com.iluwatar - 1.14.0-SNAPSHOT - - 4.0.0 - - guarded-suspension - - - junit - junit - - - + + java-design-patterns + com.iluwatar + 1.14.0-SNAPSHOT + + 4.0.0 + guarded-suspension + + + junit + junit + + \ No newline at end of file From f09578c091f9536ecba2a45589866bd2fa1c9a0d Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Mon, 9 Jan 2017 21:25:24 +0100 Subject: [PATCH 194/492] further POM rearragments #69 --- guarded-suspension/pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index 8326a6e96..9e44d410b 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -23,16 +23,16 @@ THE SOFTWARE. --> - + + 4.0.0 - java-design-patterns com.iluwatar + java-design-patterns 1.14.0-SNAPSHOT - 4.0.0 - + jar guarded-suspension From 7423f47daac7d84d4e3fe78d85340296c2b28254 Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Mon, 9 Jan 2017 21:37:09 +0100 Subject: [PATCH 195/492] further POM rearragments #69 --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 242ae4b1a..5ddd3bf98 100644 --- a/pom.xml +++ b/pom.xml @@ -134,7 +134,6 @@ event-asynchronous queue-load-leveling object-mother - guarded-suspension From a20abae21cd990965adea18c2647345b2729fafe Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Tue, 28 Feb 2017 15:06:50 +0100 Subject: [PATCH 196/492] apply changes from review #69 --- guarded-suspension/README.md | 8 +- guarded-suspension/etc/guarded-suspension.png | Bin 8011 -> 10318 bytes guarded-suspension/pom.xml | 1 + .../com/iluwatar/guarded/suspension/App.java | 76 ++++++++++++++++++ .../guarded/suspension/GuardedQueue.java | 8 +- .../guarded/suspension/GuardedQueueTest.java | 8 ++ pom.xml | 4 +- 7 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/App.java diff --git a/guarded-suspension/README.md b/guarded-suspension/README.md index 01c03f192..35044f9b2 100644 --- a/guarded-suspension/README.md +++ b/guarded-suspension/README.md @@ -10,12 +10,12 @@ tags: --- ## Intent -Use Guareded suspension pattern to handle a situation when you want to execute a method on object which is not in a proper state. +Use Guarded suspension pattern to handle a situation when you want to execute a method on object which is not in a proper state. ![Guarded Suspension diagram](./etc/guarded-suspension.png) ## Applicability -Use Guareded Suspension pattern when: - -* the developer knows that the method execution will be blocked for a finite period of time +Use Guarded Suspension pattern when the developer knows that the method execution will be blocked for a finite period of time +## Related patterns +* Balking diff --git a/guarded-suspension/etc/guarded-suspension.png b/guarded-suspension/etc/guarded-suspension.png index db962e539b40d41364de4496a41d1e6542f8cfff..bd3fa5661fab47538fb3df095fecd6bbfba7217b 100644 GIT binary patch literal 10318 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 literal 8011 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 E0VIn*qW}N^ diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index 9e44d410b..e3a13f2c8 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -38,6 +38,7 @@ junit junit + test \ No newline at end of file diff --git a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/App.java b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/App.java new file mode 100644 index 000000000..8747c84e5 --- /dev/null +++ b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/App.java @@ -0,0 +1,76 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ +/** + * Guarded-suspension is a concurrent design pattern for handling situation when to execute some action we need + * condition to be satisfied. + *

    + * Implementation is based on GuardedQueue, which has two methods: get and put, + * the condition is that we cannot get from empty queue so when thread attempt + * to break the condition we invoke Object's wait method on him and when other thread put an element + * to the queue he notify the waiting one that now he can get from queue. + */ +package com.iluwatar.guarded.suspension; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Created by robertt240 on 1/26/17. + */ +public class App { + /** + * Example pattern execution + * + * @param args - command line args + */ + public static void main(String[] args) { + GuardedQueue guardedQueue = new GuardedQueue(); + ExecutorService executorService = Executors.newFixedThreadPool(3); + + //here we create first thread which is supposed to get from guardedQueue + executorService.execute(() -> { + guardedQueue.get(); + } + ); + + //here we wait two seconds to show that the thread which is trying to get from guardedQueue will be waiting + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //now we execute second thread which will put number to guardedQueue and notify first thread that it could get + executorService.execute(() -> { + guardedQueue.put(20); + } + ); + executorService.shutdown(); + try { + executorService.awaitTermination(30, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java index 47939141f..89b330bfb 100644 --- a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java +++ b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java @@ -31,7 +31,7 @@ import java.util.Queue; public class GuardedQueue { private static final Logger LOGGER = LoggerFactory.getLogger(GuardedQueue.class); - private Queue sourceList; + private final Queue sourceList; public GuardedQueue() { this.sourceList = new LinkedList<>(); @@ -49,7 +49,7 @@ public class GuardedQueue { e.printStackTrace(); } } - + LOGGER.info("getting"); return sourceList.peek(); } @@ -57,9 +57,9 @@ public class GuardedQueue { * @param e number which we want to put to our queue */ public synchronized void put(Integer e) { + LOGGER.info("putting"); sourceList.add(e); - notify(); LOGGER.info("notifying"); - + notify(); } } diff --git a/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java index 45251acbf..41eaccd49 100644 --- a/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java +++ b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java @@ -47,4 +47,12 @@ public class GuardedQueueTest { Assert.assertEquals(Integer.valueOf(10), value); } + @Test + public void testPut() { + GuardedQueue g = new GuardedQueue(); + g.put(12); + Assert.assertEquals(Integer.valueOf(12), g.get()); + + } + } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5ddd3bf98..d2ea715a7 100644 --- a/pom.xml +++ b/pom.xml @@ -121,7 +121,7 @@ factory-kit feature-toggle value-object - module + module monad mute-idiom mutex @@ -134,6 +134,8 @@ event-asynchronous queue-load-leveling object-mother + guarded-suspension + From 449aed1a5346f7cc2c58c76aa7f39368f32c7ed9 Mon Sep 17 00:00:00 2001 From: Robert Kasperczyk Date: Sat, 11 Mar 2017 12:02:04 +0100 Subject: [PATCH 197/492] changed parent POM version #69 --- guarded-suspension/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index e3a13f2c8..b51de54e1 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT jar guarded-suspension From 8632bafcd7dfc28c141dd24ad258da9abe951c10 Mon Sep 17 00:00:00 2001 From: Kamil Pietruszka Date: Sat, 11 Mar 2017 12:24:48 +0100 Subject: [PATCH 198/492] comments, tests and description --- .../iluwatar/api/gateway/ImageClientImpl.java | 2 +- .../iluwatar/api/gateway/PriceClientImpl.java | 2 +- converter/README.md | 16 +++-- converter/pom.xml | 4 ++ .../main/java/com/iluwatar/converter/App.java | 29 ++++++++- .../com/iluwatar/converter/Converter.java | 27 +++++---- .../java/com/iluwatar/converter/User.java | 45 +++++++++----- .../com/iluwatar/converter/UserConverter.java | 40 +++++++++++++ .../java/com/iluwatar/converter/UserDto.java | 46 ++++++++++----- .../com/iluwatar/converter/ConverterTest.java | 59 +++++++++++++++++++ 10 files changed, 219 insertions(+), 51 deletions(-) create mode 100644 converter/src/main/java/com/iluwatar/converter/UserConverter.java create mode 100644 converter/src/test/java/com/iluwatar/converter/ConverterTest.java diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java index 10f8625c5..ebabfe839 100644 --- a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java +++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java @@ -35,7 +35,7 @@ import java.io.IOException; * An adapter to communicate with the Image microservice */ @Component -public class ImageClientImpl implements ImageClient{ +public class ImageClientImpl implements ImageClient { /** * Makes a simple HTTP Get request to the Image microservice * @return The path to the image diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java index aa2686845..87f44761c 100644 --- a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java +++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java @@ -35,7 +35,7 @@ import java.io.IOException; * An adapter to communicate with the Price microservice */ @Component -public class PriceClientImpl implements PriceClient{ +public class PriceClientImpl implements PriceClient { /** * Makes a simple HTTP Get request to the Price microservice * @return The price of the product diff --git a/converter/README.md b/converter/README.md index cbca98e8f..190ae8bfc 100644 --- a/converter/README.md +++ b/converter/README.md @@ -10,16 +10,20 @@ tags: --- ## Intent -TODO +The purpose of the Converter Pattern is to provide a generic, common way of bidirectional +conversion between corresponding types, allowing a clean implementation in which the types do not +need to be aware of each other. Moreover, the Converter Pattern introduces bidirectional collection +mapping, reducing a boilerplate code to minimum. -![alt text](./etc/converter.png "TODO") +![alt text](./etc/converter.png "Converter Pattern") ## Applicability -TODO +Use the Converter Pattern in the following situations: -* TODO 1 -* TODO 2 +* When you have types that logically correspond which other and you need to convert entities between them +* When you want to provide different ways of types conversions depending on a context +* Whenever you introduce a DTO (Data transfer object), you will probably need to convert it into the domain equivalence ## Credits -* [Converter](http://todo.com) +* [Converter](http://www.xsolve.pl/blog/converter-pattern-in-java-8/) diff --git a/converter/pom.xml b/converter/pom.xml index 53eca720b..026f30d40 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -14,6 +14,10 @@ junit test + + com.google.guava + guava + converter diff --git a/converter/src/main/java/com/iluwatar/converter/App.java b/converter/src/main/java/com/iluwatar/converter/App.java index 91fbb98f8..1d6076fd9 100644 --- a/converter/src/main/java/com/iluwatar/converter/App.java +++ b/converter/src/main/java/com/iluwatar/converter/App.java @@ -22,6 +22,18 @@ */ package com.iluwatar.converter; + +import com.google.common.collect.Lists; + +import java.util.ArrayList; +import java.util.List; + +/** + * The Converter pattern is a behavioral design pattern which allows a common way of bidirectional + * conversion between corresponding types (e.g. DTO and domain representations of the logically + * isomorphic types). Moreover, the pattern introduces a common way of converting a collection of + * objects between types. + */ public class App { /** * Program entry point @@ -30,11 +42,22 @@ public class App { */ public static void main(String[] args) { Converter userConverter = new Converter<>( - userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive()), - user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive())); - UserDto dtoUser = new UserDto("John", "Doe", true); + userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive(), + userDto.getEmail()), + user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), user.getUserId())); + + UserDto dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com"); User user = userConverter.convertFromDto(dtoUser); UserDto dtoUserCopy = userConverter.convertFromEntity(user); + ArrayList users = Lists.newArrayList(new User("Camile", "Tough", false, "124sad"), + new User("Marti", "Luther", true, "42309fd"), new User("Kate", "Smith", true, "if0243")); + System.out.println("Domain entities:"); + users.forEach(System.out::println); + + System.out.println("DTO entities converted from domain:"); + List dtoEntities = userConverter.createFromEntities(users); + dtoEntities.forEach(System.out::println); + } } diff --git a/converter/src/main/java/com/iluwatar/converter/Converter.java b/converter/src/main/java/com/iluwatar/converter/Converter.java index 7f7a702cd..eeabc4102 100644 --- a/converter/src/main/java/com/iluwatar/converter/Converter.java +++ b/converter/src/main/java/com/iluwatar/converter/Converter.java @@ -29,6 +29,9 @@ import java.util.function.Function; import java.util.stream.Collectors; /** + * Generic converter, thanks to Java8 features not only provides a way of generic bidirectional + * conversion between coresponding types, but also a common way of converting a collection of objects + * of the same type, reducing boilerplate code to the absolute minimum. * @param DTO representation's type * @param Domain representation's type */ @@ -47,37 +50,37 @@ public class Converter { } /** - * @param arg DTO entity + * @param userDto DTO entity * @return The domain representation - the result of the converting function application on dto entity. */ - public U convertFromDto(final T arg) { - return fromDto.apply(arg); + public final U convertFromDto(final T userDto) { + return fromDto.apply(userDto); } /** - * @param arg domain entity + * @param user domain entity * @return The DTO representation - the result of the converting function application on domain entity. */ - public T convertFromEntity(final U arg) { - return fromEntity.apply(arg); + public final T convertFromEntity(final U user) { + return fromEntity.apply(user); } /** - * @param arg collection of DTO entities + * @param dtoUsers collection of DTO entities * @return List of domain representation of provided entities retrieved by * mapping each of them with the convertion function */ - public List createFromDtos(final Collection arg) { - return arg.stream().map(this::convertFromDto).collect(Collectors.toList()); + public final List createFromDtos(final Collection dtoUsers) { + return dtoUsers.stream().map(this::convertFromDto).collect(Collectors.toList()); } /** - * @param arg collection of domain entities + * @param users collection of domain entities * @return List of domain representation of provided entities retrieved by * mapping each of them with the convertion function */ - public List createFromEntities(final Collection arg) { - return arg.stream().map(this::convertFromEntity).collect(Collectors.toList()); + public final List createFromEntities(final Collection users) { + return users.stream().map(this::convertFromEntity).collect(Collectors.toList()); } } diff --git a/converter/src/main/java/com/iluwatar/converter/User.java b/converter/src/main/java/com/iluwatar/converter/User.java index 8a4e9186c..f40c01e79 100644 --- a/converter/src/main/java/com/iluwatar/converter/User.java +++ b/converter/src/main/java/com/iluwatar/converter/User.java @@ -23,44 +23,61 @@ package com.iluwatar.converter; +import java.util.Objects; + public class User { private String firstName; private String lastName; private boolean isActive; + private String userId; /** - * * @param firstName user's first name - * @param lastName user's last name - * @param isActive flag indicating whether the user is active + * @param lastName user's last name + * @param isActive flag indicating whether the user is active + * @param userId user's identificator */ - public User(String firstName, String lastName, boolean isActive) { + public User(String firstName, String lastName, boolean isActive, String userId) { this.firstName = firstName; this.lastName = lastName; this.isActive = isActive; + this.userId = userId; } public String getFirstName() { return firstName; } - public void setFirstName(String firstName) { - this.firstName = firstName; - } - public String getLastName() { return lastName; } - public void setLastName(String lastName) { - this.lastName = lastName; - } - public boolean isActive() { return isActive; } - public void setActive(boolean active) { - isActive = active; + public String getUserId() { + return userId; + } + + @Override public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return isActive == user.isActive && Objects.equals(firstName, user.firstName) && Objects + .equals(lastName, user.lastName) && Objects.equals(userId, user.userId); + } + + @Override public int hashCode() { + return Objects.hash(firstName, lastName, isActive, userId); + } + + @Override public String toString() { + return "User{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + + ", isActive=" + isActive + ", userId='" + userId + '\'' + '}'; } } diff --git a/converter/src/main/java/com/iluwatar/converter/UserConverter.java b/converter/src/main/java/com/iluwatar/converter/UserConverter.java new file mode 100644 index 000000000..9ef1d03c2 --- /dev/null +++ b/converter/src/main/java/com/iluwatar/converter/UserConverter.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.converter; + +/** + * Example implementation of the simple User converter. + */ +public class UserConverter extends Converter { + + /** + * Constructor. + */ + public UserConverter() { + super(userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive(), + userDto.getEmail()), + user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), + user.getUserId())); + } +} diff --git a/converter/src/main/java/com/iluwatar/converter/UserDto.java b/converter/src/main/java/com/iluwatar/converter/UserDto.java index bdadf6e39..8f55bbe0e 100644 --- a/converter/src/main/java/com/iluwatar/converter/UserDto.java +++ b/converter/src/main/java/com/iluwatar/converter/UserDto.java @@ -24,44 +24,62 @@ package com.iluwatar.converter; +import java.util.Objects; + public class UserDto { + private String firstName; private String lastName; private boolean isActive; + private String email; /** - * * @param firstName user's first name - * @param lastName user's last name - * @param isActive flag indicating whether the user is active + * @param lastName user's last name + * @param isActive flag indicating whether the user is active + * @param email user's email address */ - public UserDto(String firstName, String lastName, boolean isActive) { + public UserDto(String firstName, String lastName, boolean isActive, String email) { this.firstName = firstName; this.lastName = lastName; this.isActive = isActive; + this.email = email; } public String getFirstName() { return firstName; } - public void setFirstName(String firstName) { - this.firstName = firstName; - } - public String getLastName() { return lastName; } - public void setLastName(String lastName) { - this.lastName = lastName; - } - public boolean isActive() { return isActive; } - public void setActive(boolean active) { - isActive = active; + public String getEmail() { + return email; + } + + @Override public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UserDto userDto = (UserDto) o; + return isActive == userDto.isActive && Objects.equals(firstName, userDto.firstName) && Objects + .equals(lastName, userDto.lastName) && Objects.equals(email, userDto.email); + } + + @Override public int hashCode() { + return Objects.hash(firstName, lastName, isActive, email); + } + + @Override public String toString() { + return "UserDto{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + + ", isActive=" + isActive + ", email='" + email + '\'' + '}'; } } diff --git a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java new file mode 100644 index 000000000..45cebc4e6 --- /dev/null +++ b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java @@ -0,0 +1,59 @@ +package com.iluwatar.converter; + +import com.google.common.collect.Lists; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import static junit.framework.TestCase.assertEquals; + +public class ConverterTest { + + private UserConverter userConverter = new UserConverter(); + + /** + * Tests whether a converter created of opposite functions holds equality as a bijection. + */ + @Test public void testConversionsStartingFromDomain() { + User u1 = new User("Tom", "Hanks", true, "tom@hanks.com"); + User u2 = userConverter.convertFromDto(userConverter.convertFromEntity(u1)); + assertEquals(u1, u2); + } + + /** + * Tests whether a converter created of opposite functions holds equality as a bijection. + */ + @Test public void testConversionsStartingFromDto() { + UserDto u1 = new UserDto("Tom", "Hanks", true, "tom@hanks.com"); + UserDto u2 = userConverter.convertFromEntity(userConverter.convertFromDto(u1)); + assertEquals(u1, u2); + } + + /** + * Tests the custom users converter. Thanks to Java8 lambdas, converter can be easily and + * cleanly instantiated allowing various different conversion strategies to be implemented. + */ + @Test public void testCustomConverter() { + Converter converter = new Converter<>( + userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive(), + String.valueOf(new Random().nextInt())), + user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), + user.getFirstName().toLowerCase() + user.getLastName().toLowerCase() + "@whatever.com")); + User u1 = new User("John", "Doe", false, "12324"); + UserDto userDto = converter.convertFromEntity(u1); + assertEquals(userDto.getEmail(), "johndoe@whatever.com"); + } + + /** + * Test whether converting a collection of Users to DTO Users and then converting them back to domain + * users returns an equal collection. + */ + @Test public void testCollectionConversion() { + ArrayList users = Lists.newArrayList(new User("Camile", "Tough", false, "124sad"), + new User("Marti", "Luther", true, "42309fd"), new User("Kate", "Smith", true, "if0243")); + List fromDtos = userConverter.createFromDtos(userConverter.createFromEntities(users)); + assertEquals(fromDtos, users); + } +} From 3a243eee6e77f46b72711706771b2d6e1394c525 Mon Sep 17 00:00:00 2001 From: Kamil Pietruszka Date: Sat, 11 Mar 2017 12:47:58 +0100 Subject: [PATCH 199/492] diagrams added --- converter/etc/Converter.png | Bin 0 -> 19389 bytes converter/etc/Converter.ucls | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 converter/etc/Converter.png create mode 100644 converter/etc/Converter.ucls diff --git a/converter/etc/Converter.png b/converter/etc/Converter.png new file mode 100644 index 0000000000000000000000000000000000000000..01435ef5ae29dbda20c7078291a8c1c912003000 GIT binary patch literal 19389 zcmcJ%by$_#+Bd4A6Qre^NlABigLFuDcc-+ZG$J4^-QC?K69MT4=@Jm6^E}{kt^Mw` z_Ws`QI_L1u9M_!BGsZo}xbNTHgviT^Bf#RoK6>;BLE@E&;-g1T+8;f7{1N5}@Xduo z=J2COQUMYof=X{v_EK%b@m0NU%g}B}FP}`%|9pv3B9E?2t0ps$TZpD9gG(p&LM1d@ zU&_kw^(YI4VU4O@Y~cHw?$KY|3Rl4|5y&sr3|FE2{I{Sk!1R_Fywyoxnd zHdT)8_0jE6YMbd$+J)o6d}<!8C-Yh20gvOx{Lj6J#{f}}Br{cAq3#D? z`Sif|pYk{%zSAvNb?%Q?u!J(5waK;c)6u?C*`Zg~qCyefG7_{s);HXiswS{=ZdVj3 z`l<|>?GFx0qq~_S)$7`>Qo(|3@>DXSzgj;Sj?P=w-?^AMSO0^+{-QkGB;XIQDJwlJr?OX9wN=E3w*hxF^~LMiaH z3-X#eHfbuf!qCi@Bb{+7UMMefsERRs+MgtXZUi*W7t^Z_qebL{*Scz(LoZ5HhTH=S zaRR@IeU)n@d&0QO{^D#a$+v#@xaG`h{%UXPP64lH*!$vV*V1j+Tixrt9D1I+^ly2? z-m2H7F8u6)8s!gn9M_z8G(JJa-UgDA=1ZXH1 z3A5c(;CP{Cj3L!nJfuzba16@3<}e2^8rjOW#5HMkkZoXf>y!Nj-KO2+i4f+Sk>RE5 zuc~*)u5Cx;eg@06aZz4I)=T)iY4z6YtKRy_zOQ_iC{5F0J5~EdtfRlLam9>VORB!J z@O6Y}Mhu~WIz7W_Nq?S)||FoXx?M2_d+LF(~j}G01bAEd; z|9L;s-Ol_Gd#QBz&fVhqgy}n^#VY&r3?H56u$n8XVn_id;Li2H)=L)>Wzz}*7|V-_ zag-&IwQ%1bQcNHN9kYXp=mEv}C{Yu8>yf6lkmiA{dCtrUh;#hci`%53r|sW(eM~op;i@ zSWHCnS}$#CJuK)NzFAjot#dg#qC8Zk@!9zv9p!n0y3)3Nbi{+4Yacd(Y0Hcp3fGU- zz1zbb!3DW~@(iMB&WLPioCyPM$Rg+_OXGTxVEj`1b>U2^?B?D}jZ|n$v_fZsU?n~F zd6D@ne~`g<%iS*BmfcSgSBRdwpM9&uyLBsQCe8Lc7`Z0;-plwMT~AL8nCgfWIT8z% zq}t#FS1k3N^p`-N@!9`~x;tfFIY>iVNF&jnHX_%p!j_Q#M9ux?;!Bj7v$sh8$*4Ni zZ|{EFetQnTHdx5=rdr;H(Tm9^nMn%oCH8TF_BhB0CI?MO4G1laP!92t1U_! zX7)$~8(@i#Qo$OjL zUy=Q^Vtft>Zl)y`FEXp&!=cNxHiZ}A$*Q7%d0|NZKIu+bW`h=qIo*u2lD1L$mJZ&t z0X_&fOQCvNOshnv{e=r31<6tPlR<;c zn$RH4vSs2~mmYyv`*Igs2;HuzUXF*CUrT#gjkXlW%eQ18^kGqpcJ@ayd6iaD_^)eE za&WNsrc|?)B&cj#v~;+*93P8MpQML>u7YI=)1IQjv1tpkb{Y{_^XNTl4F6yzr)B3u zES^D7@vYxWrSjHlcYuxQG%v;-gOswbRoUhz?n}cWG`oOQBuFq%mO$0CTS?~fq~)|2 zIfBS-QB6O4_V%c2tZlY4c1t=+(krGu@m+sc6a6PsJ-)i$M`E|3_tNw*ehit&Tb&GX}rhRQB6d2bfyZlsJ zJilpE(E|rKzY43p&GH+H`9oV9*MKr_SAFq`{$P3tL`VPpfPROcVEV;x?Vcix)J+;? zQ8ty#N4`xuTo3?e-7%{NZ@!{c7N(E0Yk9hw8VVbBz}rJ{Run**TJ+(BHFb}`q@qMn zy^$+4SW+dOX7wVUOwyW1FkxW&&4P>%r_%>B^pZvhEP_bAiAzIv+fjt?0g>c(I@O30 z1z!sld^e4ixjfw!Z6EOqxEpU2!p)42N~tl);v?M9UtVg67L_{SKpn>L-->*xxP$Fl z`g~`5+>Y&TB)7M*Dc3Mdd6Ou(|2Dga3I}3k~9c6LzCab*PHA zu`L(WAz@T1a!0@YDtjg+OvuhD#W{w{Nbt=CtI}A zZJo%*UqC{q2rF$dCQnNyXsqkg_cY2#IiQZ5QP>OgkOJ%-^UM1M8_p+Q1k|46NRTql z{tzo*4S90Y35i3YpDrzUBdpuVW?n#~WBztj*8lu9CQOt+aO7M=ln5ePmBHV`2QtGw z2VyZR5dw6g7CZfTk+)q!nF{e0M9L0kl_WY|uD5myOsZQs$kRDHe`bPdSp{Q96~9~1 zBP#8i#Lc4-DP^f0Pt0R~gBQ-dGm7wD^OHTzF?pXzk=cau&^XlL{$*kTLI6!M9@H}K zD7^g^EzKn?iL#tIl>Te|4g#1S#;;Hcp)!b&oKnQBs_!RXDyHen8Mo*?M&eN3ZOo@@ z9Zjgc;WUC?Cys}Dm{ZmqTx>h^9n^UaoAuWBD@XyuBQOJww}CeqA>bHR*j+gK3bw1X zGldaZ(b`_$5*nm5y_T-Ev%>(QzsQh@3i0hZ7XR|}GA)>#n}XaROlR1fHeTB0eB>Bo zc+_F+nUK5~K)JoFA-K|<6*;h}ym=fZXxz~2D0Dz6s+mL?c^Qmf(SOu#03H{N9hEgU zhcwaI7_Q%j)Ymwe;#!02^iWzc=~0v7rBgqSraFgTeu6ZV+f^$E!oW3-2m*8vdCnR zn)-D8rQ&4|E3XCPhy`khN)h;f=WP8?ROobCR1iC`-+TA8N#M5ykB$XHndp}Ev8e?Tz`##uFn+G#KTy=s5FWw zBUr6LIbz|jmf;IC^@T2pShx9;aaOEvzKB}fc#JW)(576=8AS4E&egNC1_-| z-mZQ`r;~G9vB&v`CW9*YeQ}C-PbL4%* ztn-NsQ;zUf2nV`6sVaR5syI9x(%2)&V?nm>CstpJ7!dSR)#S2mf$sdMrZPB* zBgr7_BkBPj^lfr)-6?lg3Cy)C*QY6fKT}X7m~$Y8 zhI4?NpK}gFzS%RR9xNu{&3xKQyfp%Vt*JB79lWT`&s^jCeqFg+V5_oxzS(Q{J%>6} zSZn92y^3nza!TcGetA47UgT#pYw0QW&J=<&kv6LoL$g<-Y@i!s`bIz~nEV|2U3D_X ztNa~a6m&5Hrzh(u2^D>~@x=rjUdFJY2YzB~+AtMP5LquZXy%%|&l+PPQ^xRJGU5{H zL&;*fGu5j(CJ^!cNiBM;PlwC4+N{sT63!kcV7=+PwG%GuaA75Tf-6B1pco791PFYP z?1xOjX(zZWfn|S=Tgy|91>=mo zu4e7;{q|W&>AZbj%KLe1?txy=x)sD>@0qr7j6g&5E4~k{ABhuL`GIzW>3pxQ_$OjHajXQa8lfk`;yX?fIz7vTIVm zE|e3$*K_ONK?c{$dtPl7*H>*9HT>tdch^#TeNfz;A3^KVvP@72AkLrpDk#{`A>0zx zTyP^6F`Pxd(^orrP`h@Qn8P7~v-h|YfdF~NgeMuZEvdfLD~RZB%ZN`mMme8}&_yFC zOlg}E+sVgHGGa8S$0!M|E3q=x%p#AFa$tW)-N_BfUTb#>PbGa2KpZF{%Gz6DKW)7j z|05qB7a=rMA8SEQHy#}8H(BSp_LHk?9dz3iktle1%$VdeZ$EIwY^4-R=BBkUoU6tX zs!NI4%E*;Xl###wB(i6xNp|Oe8KN>$_z>x+1cZgo91f!IXLx~L8SAgJ|nnz+HEEIs#mi^vQo{id0|qg0Lx~2C<~vhIIjN_f_z}7 zcP*9f-m$lHq!?0$3u9hY1zXKutMmM9X^)BB@uYS*EJvOk{4 zLrl?hKfIg?)?CR_ql^oo$*3&pC(3hrTZiwa%|o1b_1@m<5%(fM_306>P^8Oh=}h4Hh6oGqLCMtJ zYXbh>lgo&_tsUDsl@wKKhZNwzA?glJa+I&_HD#H$)53z;LjGg2XgKmSD|`(fYvY?E z2x`1)cju?UE(7Dj1bgHh>-S;0#plSlKd%b?dT64q`uAo$%V-%m@~1~czhFZ}d&^*< z4dH~%7W*@?@MU#;TwOs2IRyiuU5Eon=*Q5q@YSbQpP!J+9qPUwzjHH+mp6L!uI~q? z&7SqzQfTJvTi>>=yx^MYi6u(hxuLo2G54wGDWA6tgGZ!ta(an#rLY#y#I}SSZ#yfv z9ie(jd>7%ga*)Ru@ z(tS7*VEO8(XN}#vd39PwPja>g>ejx(-hK%E?enn1KXr=yZQ=Y!l)R6Easxa@E-t|g z*pMlqUpZtrn9qme@W%`J9Ho;e#$NoRyTy$a3x&asT<{^6Qt{hRd6kA};!xESD57Fv zjp`FZbf-@M#wB7SBE$r|jLCh)uQRd1D)FJK|EJG6Or9I95sf0{7=T8bqO|H7&GGua z@TOlsyI4%5cS(?UFeDh7jKGm6OMK7-aUGKGxlxQct5|{`yfrpXin~5TauLSEx?tZ| ze%oeUaNggO67lHZ`wHBItfOo!)Clv)X;fdT{X8}@4?KP1I4xU(;T<;htP+_}Dlda*wndni(vp?Arm_Hl2#Q1Bfa)QhEW z>w!Wb1EJU%13+m`9UnYAj}{kS8-F{toW+ z->j^xh(kKxEy3uI@c_Le+wXH-g(Knge>;LLdZ zFrC;?P7h=|hmsF2pzt@|+P8ZL}uypmm0 z+^5;9cOPU-!E3kGfHzpzeXBvY$w1yM@FnKA2o7KelVHm3&u~@W&O$ENHem|IRf501UIp>1nn!c4n)iuIsg4 zuZB!m!_)&(kh~kU8QoFo%`mzQ#;p+=D`kcc2!HccewZ&<@eumb8+(?S|F<v z*m`dCgITsh{_63#_=#zX`4RKb#qa#aIt%DYP<2~&`j!6T@1^h4Tt*RsZV$m53V0%{ zYS@&3Vru|F5IlG$IzHZ~!e+9dpVUVG-txbq4rh}u%$S=vc1vFkA$+}nm2Y175vxqiBb=zj?8SXm-!uXit#*-p6{z&c-W{N3;PE*)GnO*bVksu zCkR!0(HD$MW)+{Jg`}8yP)+9UWr9|wbC^4nCJppcu!3izJd+%?CsLwBcPL}_h!eMF z9q^f^PNV@*Q7J_<*3%FL5i6(`f?m%ysMkBjVVaP6qz&7vmu=BmvXV<=_?k8O_9?%b z3xw}ppyzSey8gCa_i4ucCR`2cs*K?}!suD{^~Q99v?Vf`6DDm8v#!)nVaxt%43K|d zND&TQ@2*ULb*2GHS1GxURsB5DC6-u+A8%9c{44sFu`OM1YXw(PPw=9_HSKI^7alGm z^URm@VlDiYtm;&4_)nzF65b|AM@?rC}h z)}ytnPreB75YbY^fvaM(b+ay9(MDSEZN30ieRy0ENlTo|Hsw?>ir0o(L)s2o{-hd5 zwWRwNjFiQucpGS<_sdm1jVgg>pJdgdok)`UCkh|rB z#UxSuRw3AcQ$E9hIVSQ(XVfQ$8|tRiYM=9KXiwA7tId+BES6CdaApiHJD)R3F-U0N z)t79hJzeYD4nr7GY@?HxN$8SYNT5ULCnBbBtDwS@jlmj+hBD<~M0T?&`o(nU@dCgF*j^ffwRk7R*#t1kmPqgk4f zG{%!n(zU~W#8XK z`!FUAyY<9vf@Z>DBR0iDN?7q!J>a`#&6T--dcUtuv#4G$u-?S|PY5OIqKG7IqASxF zvZ$9qf7aWrnJDIm#)90disi_F+<|Vq?feP|&PB@-sRjJHo+2#ITpe3<svbJ};~5j#AB>DAOCDR-NzVm>6#g0G zcKXsrEiI^TzWI9-te?w}D=jz&`F_n{QJgWqw&$6I*SK^VXi>b-mMedRixt}!Sc<3( zj~jAa3Chi(HP56ocidLhyqt(WeDh+@(mtIJYOvzS0y;_5bm9P}dcGH6;vLrjm9e|g zHkx%0mI!#^IqOlEku-Zg&%^$2ef$PQS!#LtC){NGVwLaH?1#EdK%9NTTRM3YUKJgUXD!!vStG+XR50u?%y6i*feYJ6XkujOe}q`kd8Ru` zznhuYz78?rOtxIl!Da4Sh16#@l}=C&(azE>BwW@+0EqiLW-a-@%2!w61~a6(#*TPs zT@iKA{jOXveg+bf+{91+zm17o86XAFo}8;CW7V+l8AaAUR~eAmXVKX2L;du$V0cYJ zRGOQ0s3p~dAUDlfG6{v$PyZvkt==oW7;f=59R~wEKDS?-I4A~|nlexIACqOX#nZjF zkoC@X%Q9Ir|GsYSbi(FpLCjjMVdhvpEA-poc}sO~@Z=ZEVC$+WFB!{*#tX&fYDMHy zL`^31il{>=WZ3;IWcs3{A;HaU1|C)Ilh&Pddh(wA;4J2?T2Fs`9yXiV%Nn@X7CAO3 zB^Wb!CAHBx2>*}Tg;GutAygRfaNp?XHihN zF@_JS=D~Sm<*5Kg9`TJAr3X89FhX)il14pu_=@Vg^ZfV_)Cu^SJodS>QqO0UgL7?& zZRKfZe4H0^JL@KGV(=(&EV}Z{+oz<1vZc>t+AlB6xq--+b6kreXl1KN4xgj$c;%$( zMP2v3s}z&{^P`nEQ=J>rup0&DLf1>(l7jMpA9FIwrDO+)lb_*&))u_!1~Zy(6v*P zl1$})_89GNO9OIor8Ak;Jww^Y;Y`~SR6mMZWA`@!HcJJ;Qj$#q;+Wm%Udc7wau+l8 zO&OoF7pe*S&-&dwGE3r}%Cbr7aAEe8y2%hchCKoqZvv-&;qGTv;k63_o0LQ6e7K{k zc+ZBJ(rC{RizJB~YIk{N0$ES6B>Sg52OHLhgZxLQlPbm*eC#1zjJ_aXwDdlFsk&Kf zT;TkcMVR-{p$v10CZ>yJ`UPdoB?m1>j=tznvP@a8i|h=P!nA-{9&r)05T|sV2N+fh zUmc~!>)^62eD|bGn2OB}`nxDZm98#4J%wZ>Je?+P7!e{$y5N$jT)ji}-weZ1^s=+N zs2rQL@+=()M=3dyGTi3;1Q0TW#e&%jY*C5wbP7^6>lKV`C}S9X_tAcFTt=E)g`0W3 zR{#x2b30PSwvby#s%kVzD3Zw4U|$w{*^Rdl+*|^of>({-l>~0>!v(yMm`cFqTqur(wCKmqJJhQHI~v-s4#2nA^4X*%0ez_p&JO z&}*ik*F`WAxOvM6MaqmYb3b%>!bLQuXue$)dhKJ7H zIpN(9OEM>aM3K902{*q<<^)%;imTrk77W%XLuFl@)hb*w5aGm2axa|ie)aR`sPx=$ zRESv(LFU8-Do_g4Ukfsx=Kb#_U;n>lAu2<7kx4vkoQ=KL7ps4U6`Ukga`g-bqxMhd zjt#AtH4w_Np}#C2PI^OX_~hcdBkO<>Wi2VDMny_?RxK;1ZV?NiRPR*A*X4AcRaYuo zI$dyWSq&ZuFK!Q5u8&R*shCg{cattT$*kt{hFML-uOQmXgh$FW;iymw>d8#4<%O*S z#3x(oY>)$uB-x1syMfBFm8-(FfP3YStxs)bQDA6pB`>Rs&+LUi=GAbt0VFb!i(nv} zV^Dc6`f_ilSTiSxld~q+fWSumRiHRxDq-{WB(r8&+6y?tJM^Ho=ffCW~}CK2p&_=jK5?RzExFWqmi5S z#4A-${7mkFXYD~E+$Sb{95>{Bk=%-5nijK zi6mGln6?F_bq%fqy@=*?(^a%PoR?l^`njq(ycR#dLo*Qoq1t0#GxH8>1lc{QxxmBu z!je%crASK}QvrPHJ!x%2$%wsQMQmJJOMy!2o$(_!8PZ|{E6uR73_jy0%kIcyIsas__>e@|>7^9k~_eNzn z5q;wJP&CKeign6)HIA!@rb;~0fSR12le-G;a6sO4vDQw8`1OTS!dT5V!pF0mJ>uQ@ zoddoV*s(t2H}!Sc!NH^JMB!46xLv0aW~L-`i9avJG;Lcs0P_n@3m?>A5SSU1xRnD9`WgVCt)ex?F2radc#qnWsRAtjkHJd5YJBWtzRGay&9s&Z#mB&He4w? zr%;hJK0*laJ`1hM#0~zgnR=M~FIU}LA%bfC;a1{R$#ftswkl4sU~Wg(rFdo7q03sEdat zcjn85xz@y$#li(6YRRNvbt5VOKLh?*4lE(-24s z0hOt@_o<-D5Zm@RK;u2JP2Qo?t3HWO2xghpOeI%&I_{PI# z;J1Fb>^9e@ws*DXny$hEH(-h`#clxspvIRXpv>oHcSTye&AVkk=_gQBdC*uOoDQ=M$!ss9-T~{G|3uVycuBBZ&qc!~bS_w0Ya|JLS>}i|BHy zo}z;u*P2avBIrp8P)r=+`?)g$aCm?CA~j#_HyK=v=1ARmx9wy2Uh2a^#C5%P+8c5( z%hDq1$@oI!9I#odmH-#M=Pon`lN`xKLcD_0*Wp7Cc>#0CkiN28L4-ePK!EDtN z>r4(7=SoI+WW%P4@T^7`uZ47ujXnlAa56Wg<*5~k%uaF4l6pIZ{ahI64`ZG*Yl4HL z81^~J(x38kfC4T;v?vZ4O26l1cgpo(5#OiTezo^%@vIeR4hrXqrhMz)Pzgua0aDET>|B zduUq8NoQ-otHl1UWHKfNt=t7pliRndG4OR$7%snCle9bm`{?f@GqJL<;rr1J1%b49 zoVkBe6?YWy*Mo!jxgrwIo*myLt4^xwa?)XRi|4#0{IFuLxjdGvujhusJ_a?Gx!E>u zsDeTl(~>O~nv-SMyqp5c6_v{mTQtH-bywZeleb9+c+ac`#Q+Td=4`>$w&i5=h&Oef4-{x#bj{7aPo1`@bGj6FjBSd-~@r0qDbg zSKpVr-tF2vGsD}!j}`BFM&>WjtdlBQuV(H3B!fcmrvraVg}99W8gpVIhpaYM-Jli` z%ZNS{ktHhvr>+=cP4n{SO4e=xwZnEOB;bxG7hu0~0Odo5@k39?puz&TOC@-pDYO?N zhzzB46d+hPMCv_en-usWSH!FoNHZq_AAk;=MyvOY`$Ea12tfV)9Vc{Nx~pj7S;*Py zceb0&Sb;O2I4Ba6iN1g1gbR=1w^_yUt@jFFB=Nbi;S2t*{`HCU6bsGDu(jt7>9sQa z(}(ZZc@s>is(Z)@{iX22JDDMIgHx$#ryA(>?&1Vu&N`b1cVk<_F}t2baf zHN-Udf(#Zl@Ts5IkHPh7&3&$n=oU!mKvQf7{S!t&jKc+I*gh*<#9uSQbo3fPbf_4R zQG?d2NSybRW>>Xot&69bt|V?#DXhVY%*eTdu?}Wz z&K|F>K6uklja`fP`louA;~POCh^%WU_X)tboeuIMM`vTU0Ku`f(*vRb3=}B+N3UP` z!W%s`{^gXh$kG_;cxc$}$ue)AIVc|#E&7+l46-1v23er1*M?xhKqUyl8iBbfHW_YT zn3Ux;%a;0%j4d`VK4st0+ch*q5D{+UGnyd)Fax0fy>Fr)(|3Y73o!T#38?c??)xX$ ze<^5r;3mMhPmR?=flM&aphHEc-8g=5b}w&qe~GFRLm=Aczl1v=)Vs}Rdo-s}^KlZ~ zpJ)JsE=}~T@?SK3=P%8m?Mf|>^)FvP0XD0}LPTLYSiua0#bO>qW5abxICe_h9LK)8 z#K9HqH)GQ4Li6s~rF5r}Enfw+D3>(62y7=W43fhAT+#TkQTJIsBpQqj*M(WAL>AN^ zq{QSIjvwgTqXxzTWv$zS%!8go!~i)?pV*1a$?6u!ZU^>>i7j}sk4eDkl84TZECcYb$voeTCInsRYBB8j^VW67?QI)Dk zx8;!VPACp>!Q5n5M8V%?9dMqVG^32nt}i1z5#V0yt@@?)Eov5=p@6eZhXLg1-y%;; z$}|#e6vUB)mZSZF5rXQ&D#a!^c-C)7$dGYSo=I#Y`!is^6qi->&YNSS#4ctegPl^O zZOfQS;p1xKoyDO=Fsyf7RS=(}GEc=F1mVB{t`+r^%M`*>;9!Z%pRFg$9;=oWmuhRn zZI|3<2Qg|5q=i1r$8lBiO(doTbk2VGOaZ+@v6bxS;2t%%%`;#>2d~eI9t*T5)$|WY zGOdTRUM4aUIQKGJ8qNqn`2uAd>$Cffz5p}HKdnvo{98(Iyerc>f|jDMH0rV`_K73h*CxUYnC0eiN?UXRV*|FvM_%`H31}v zqp)SAuhsCoi*6N@I+`c=um!8HrNh1T+c?aVquO?7;@TxPPpU;wsg~odm zCu&X-L0amWyqZ4aXQZ^bhuYQ zK=)i9RxsB6yawKa*jy6i2u}kH;YGqV0rLScib|W%)1Un%$O&&LvjzS|lS==xa&G|{ zoqhbLj0QiyUl#gL1>5};Fd0sG%Jx;>y1Y$?mwEy97--oucmjY#&tD>Y&&POwp+RqQ zaxxOn4*@_SmUPevx;1iIf6To19)I5U9~?-IdT#h`-*yA|z)%Uhg%&DqY78l#;$2cp|>XDD&hu9FZ#PQmuPzMxw8QpG|52x??0 z1rgEWeqCw*0R8H_EaKK-RniAm`y*E{D~$!IeS^|_QNXn)b6I$p98Oc7?{6^)=_i?t zftZ%Uh#FB(AwkF@+0`5wwu#E2~h$iygB~ zmwLLM!X^OsAO*z%zhnT?i4hy6#nE88`}NY2dN*G6Q++cr#;Fwn2K74A>1LHgT?tdY zv|CkjVFw38iC&#ud2iIJPNI#z-;oobcm;~eQT{l!uy9}Ve=v<((p*O1R;_qsX?Yn2 z$1H;T%CLhn;&2m8zWcGkOEcG`)N4_Fz7OD{a9e``R+RPy0=wrwddU6LdVxAW`U8WM zqdfa^aI!hL*9?8=i!5&NSe_g`E$swgwlM)_n+lVAc~+h)0pQJB-=|X$3QDkgy-$t2hFbmWicS|hsRmj1oETIZg=`EF*Di^FLM31J-?Uwo{z@2 z9-ps9O#y51{mb_N?lIv1W`CC{f#w6RgC_e`F@XQ~p#BggNF>hvMZNa_Lx_yUAKd=|&t+tguM{m=+jfGvhT|FIeg3B}UC7t=8+gC!}mNnuCFuy)pam}h_x zA2!uv=wES^NSFo((RbNj&r?uyFPN&NAoUXuqsVrq){K({*J`uxo^ zO;qw0B1^UZFvsAHCt2j5V$ie1v)$M!rY5F9~Z&$R*?EaR& z+`EI@B0eXOo!N<+_lrq@?FunodqZxD_c5*IdVhxDbOr)_s4(Pj1u>vmF}c*P%%Az# zUJj5(2$1%N($N2lw11EVX|ZOhDU9B+@8=11xzh5bR(U7THMteO4?ei$wCKa>VoduT z{ii@x?;)fJ3I)!`eT+{7vX)2|GKPQny5)|bmEH*4CYL<}fFW3!K)DP5 zUQ-hHBx~8vS}*B1w2u5vvLr8XD!i}YP53l8GC>h7GE4$$cC&n}(O+Y1`j=WI`<`;I zRT)T_{3^e7VWz=*^+6wI{Y_>Qi}lP&|_vJ9~40fxMPqZ?0e>9_WRA8b@1Iy z2dy4I2ifm=-R4hT|M)-+_n*8zAV5P)o66_ac&{J+WbHcmdrM=c!gA`$;}KdAGQ7q! zS)s|=)q4Vgj`6o{?e_Pl4Gi0PzSZAP2@LfJ?B?(B78o)haoF6m1u#s2)_PE#!0^j+ zx(BQSh8s`g@44{4A>Gk$0JH))pKUIC8i2e3e|P~^zZbgbP=~VLo2>zUZrNA4|IwyX z{rA$>-->;w+kEa$PhEb!IRCFN$^cb&{tU>@b@#3Kb{IAf(hCeXVA=m%IxzY7LJggQ zzo%_pPXE25MZ2%RcVx@)!05mP3G8?*_lgb}e!(q$ICo&^@(AefcHA7o=Xq29i_*w0 z*56YiwzEQ20D5?LstmXe;OTaI4&y%#Xc`+B@(j;4x!V4*i+8VoQb zPRGLpz&Bsf^}r0sz(BzKzYM<230NUr!F4I1D@T018j&No?6R)t#XSb;+)O@(0!U2Zl$BD1CwB3em3_wG&1Jtl-@t+FI(UxWWDIgsn(ev}acXS<`s%Y%A6=Oeo4_ z4EHVmzF%vT>Lb$ggl0u8WXuFd#l+S9eF2&t6(@`ega^SvQgw7maD%5Gi@-??2b|L1 zECiIp1lfeAt4(fXA=nz}yxu^5Sn_QsCA>&M-&w4}dvS)~rkXbJ7eR+E706Z`RukEA z5;)?X6Y8^jx*z2y$RUXw1rY-+!Qy;D8(@l<<~D}7k!GRK{cj;Xg5yy7 z^T5AQI8uS&xPyVm-xe_DF(MyIy-W8eVnrct9rW-I^yXij*Ls=ljBGrqqCozxHHh*4 zJlmxc=E@i{?ZXPDU^}0FRuQ1-Tg9_Bu7-_Ev$xRfF{D~0in&bM3Ax|rS4xIxG|)YR zQy{=U{ofBFJfRLZqRPBZ=fwGM2fKXE*{{x08&qk+SZkKblf~el0tCwv^$8TW9?LA_ z5}XfpMQNWa3RHN`?JO90?VWuW1I$R^@?L*tLhdBHUJQvUZ9bkjxIOP7y#3;Fv*b;B z%jdecjY^+-{w>S(GeKwCAf<$AhG)vh(Wmn0<0`R>dP!dTV1RBXSd|A-ZkCt6-~H~n zXX8Jgn!3GQIkGNt?K@y9WJiv%!j!ly(rfImd|sOSZJf4G0C;x`tr)bzEJyFP-$2jf zv8UPL({>jl<>PuXE@kVbN^`f;GO`*k7kcLnbYdUDi;RYWjgt~cKgp|HCYHXusCbfv z?0H;#cK#{lgo=U(e(LJ#VBWmKj%I|4ZBK4n=LC@pFF~X0nU3NU_#*Ey4nwy2(Q=P`8eBL;HtjF zN4fJ@RZYX^do$d-{O;CGv@zZkJ~JGID!t!f;+Q_4Kzp_wP5?6~5HJAeb+RWm=}pUv z{CjSZ$ufrf|J;x^e?1>hUwnNW&mR@`Kl|4E!xak%Wx8GMYxo7c;L;;$-`jlosH;ES zC$I$~Ca_7wu}o}PGBErFOO27mZeW#G*9~FahTT$I&z&ERJ{NHZC8^DxlGo@1XjYM9CA2)sFdpUEdsYFg>GCphd zOLRMIz?lUFU7Xpk3CZiGJHY2y(j2sTL+&ICKrwX`JLqOTx(;g?1%IP{haPE_vj`e@ zIr0N3=7@VmKTyavNTr<~Jt{JO-$b703^b94;{Vx1{vP-31Aj?O!v~Z<8`ajmordG_ z^^r?8icBcRWS>2@p0ELbXoG{gYvseT2^SlY?LyPiH-NKlF?j8Oi@iP(TZk?bF>3L2 zcYU(gym8Iq{==FA67-Q zD53Oqbqk|MyuEh8$|&oDJAu3uA@&lHLt2j>5NS7|5jwNk7dbEs*R75J5MhOl9)ss% z-Omc`p-X)KRl;}`*e$Z&Ul98;{Y+pjD&mhr%q4`96 z3t|X7U1_K1$G$}70=aoP+(n)$7DpGbzmU+dbAuNt%Ns9?^p%Iz0|Nr$g!ctX0pa0# zxt{%B;qh8+-My`)rx9GGx>|QHY~LBSeAA)-kI)WMP=Nv|0FP~<{g>w>w&AqcxVgKCpS4|-0s2V+4W7pk@jtt<{^gez-}h7ncemQy|F*3N3myIY|KB48 z3+UOK{d6~MhsQrCyzz{<18*;vbZfN*ag)4_{B@I6>W0m}aSXyRSnQ3cXXmwpAq zBtW_$xVcBib_9;!2I=bO5wfJ^9-4LVToup^9Q8{rM+t#e{ua+uLs|!`9p5yYZnq ze6rYIW<38qr%ZxkIQetrXIlHBKE)+_S>v7Wf!o!*dFj z;G=)h{Hthi*gf;a{HuU{@#qT}*YstUZ18*m$ph7Z#E1Y{9N?ENGzR1crb%b{FM|(r zi>2BJ2fpS+Lpl*l#K3#yKuHWX@cAgm_a37jEYtf>d7L{!mkv}`;YY9TAA2MrDl1Yd Ir04hl0JmNfk^lez literal 0 HcmV?d00001 diff --git a/converter/etc/Converter.ucls b/converter/etc/Converter.ucls new file mode 100644 index 000000000..368657430 --- /dev/null +++ b/converter/etc/Converter.ucls @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 2ed7acbc31ef08e77fc6f0808a22ad86f47354ce Mon Sep 17 00:00:00 2001 From: Kamil Pietruszka Date: Sat, 11 Mar 2017 13:02:29 +0100 Subject: [PATCH 200/492] fixed checkstyle violations --- .../src/test/java/com/iluwatar/converter/ConverterTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java index 45cebc4e6..eccb81cf9 100644 --- a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java +++ b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java @@ -37,9 +37,9 @@ public class ConverterTest { */ @Test public void testCustomConverter() { Converter converter = new Converter<>( - userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive(), + userDto -> new User(userDto.getFirstName(), userDto.getLastName(), userDto.isActive(), String.valueOf(new Random().nextInt())), - user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), + user -> new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), user.getFirstName().toLowerCase() + user.getLastName().toLowerCase() + "@whatever.com")); User u1 = new User("John", "Doe", false, "12324"); UserDto userDto = converter.convertFromEntity(u1); @@ -52,7 +52,7 @@ public class ConverterTest { */ @Test public void testCollectionConversion() { ArrayList users = Lists.newArrayList(new User("Camile", "Tough", false, "124sad"), - new User("Marti", "Luther", true, "42309fd"), new User("Kate", "Smith", true, "if0243")); + new User("Marti", "Luther", true, "42309fd"), new User("Kate", "Smith", true, "if0243")); List fromDtos = userConverter.createFromDtos(userConverter.createFromEntities(users)); assertEquals(fromDtos, users); } From 77a534385cba9b357b4e73c57c42faebe74de0c3 Mon Sep 17 00:00:00 2001 From: Kamil Pietruszka Date: Sat, 11 Mar 2017 13:35:55 +0100 Subject: [PATCH 201/492] fixed pmd violation --- converter/src/main/java/com/iluwatar/converter/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/converter/src/main/java/com/iluwatar/converter/App.java b/converter/src/main/java/com/iluwatar/converter/App.java index 1d6076fd9..fbae0309d 100644 --- a/converter/src/main/java/com/iluwatar/converter/App.java +++ b/converter/src/main/java/com/iluwatar/converter/App.java @@ -48,7 +48,7 @@ public class App { UserDto dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com"); User user = userConverter.convertFromDto(dtoUser); - UserDto dtoUserCopy = userConverter.convertFromEntity(user); + System.out.println("Entity converted from DTO:" + user); ArrayList users = Lists.newArrayList(new User("Camile", "Tough", false, "124sad"), new User("Marti", "Luther", true, "42309fd"), new User("Kate", "Smith", true, "if0243")); From 1aed5905d78689f36a9cc0b9071bb58f3759cffc Mon Sep 17 00:00:00 2001 From: Katarzyna Rzepecka Date: Fri, 6 Jan 2017 01:20:59 +0100 Subject: [PATCH 202/492] #66 Balking Pattern --- balking/README.md | 23 ++++++ balking/etc/balking.png | Bin 0 -> 21427 bytes balking/etc/balking.ucls | 46 +++++++++++ balking/etc/balking.urm.puml | 24 ++++++ balking/pom.xml | 46 +++++++++++ .../main/java/com/iluwatar/balking/App.java | 53 +++++++++++++ .../com/iluwatar/balking/WashingMachine.java | 73 ++++++++++++++++++ .../iluwatar/balking/WashingMachineState.java | 25 ++++++ .../java/com/iluwatar/balking/AppTest.java | 32 ++++++++ .../iluwatar/balking/WashingMachineTest.java | 62 +++++++++++++++ 10 files changed, 384 insertions(+) create mode 100644 balking/README.md create mode 100644 balking/etc/balking.png create mode 100644 balking/etc/balking.ucls create mode 100644 balking/etc/balking.urm.puml create mode 100644 balking/pom.xml create mode 100644 balking/src/main/java/com/iluwatar/balking/App.java create mode 100644 balking/src/main/java/com/iluwatar/balking/WashingMachine.java create mode 100644 balking/src/main/java/com/iluwatar/balking/WashingMachineState.java create mode 100644 balking/src/test/java/com/iluwatar/balking/AppTest.java create mode 100644 balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java diff --git a/balking/README.md b/balking/README.md new file mode 100644 index 000000000..e5f8a6711 --- /dev/null +++ b/balking/README.md @@ -0,0 +1,23 @@ +--- +layout: pattern +title: Balking +folder: balking +permalink: /patterns/balking/ +categories: Concurrency +tags: + - Java + - Difficulty-Beginner +--- + +## Intent +Balking Pattern is used to prevent an object from executing certain code if it is an +incomplete or inappropriate state + +![alt text](./etc/balking.png "Balking") + +## Applicability +Use the Balking pattern when + +*you want to invoke an action on an object only when it is in a particular state +*objects are generally only in a state that is prone to balking temporarily +but for an unknown amount of time \ No newline at end of file diff --git a/balking/etc/balking.png b/balking/etc/balking.png new file mode 100644 index 0000000000000000000000000000000000000000..f409eaacbb951b01f4bbeb5b6b6f51bed1a86179 GIT binary patch literal 21427 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/balking/etc/balking.urm.puml b/balking/etc/balking.urm.puml new file mode 100644 index 000000000..b0296b925 --- /dev/null +++ b/balking/etc/balking.urm.puml @@ -0,0 +1,24 @@ +@startuml +package com.iluwatar.balking { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class WashingMachine { + - LOGGER : Logger {static} + - washingMachineState : WashingMachineState + + WashingMachine() + + endOfWashing() + + getWashingMachineState() : WashingMachineState + + wash() + } + enum WashingMachineState { + + ENABLED {static} + + WASHING {static} + + valueOf(name : String) : WashingMachineState {static} + + values() : WashingMachineState[] {static} + } +} +WashingMachine --> "-washingMachineState" WashingMachineState +@enduml \ No newline at end of file diff --git a/balking/pom.xml b/balking/pom.xml new file mode 100644 index 000000000..e5b8f11f3 --- /dev/null +++ b/balking/pom.xml @@ -0,0 +1,46 @@ + + + + + java-design-patterns + com.iluwatar + 1.14.0-SNAPSHOT + + 4.0.0 + + balking + + + junit + junit + test + + + + + \ No newline at end of file diff --git a/balking/src/main/java/com/iluwatar/balking/App.java b/balking/src/main/java/com/iluwatar/balking/App.java new file mode 100644 index 000000000..8fb0edcb0 --- /dev/null +++ b/balking/src/main/java/com/iluwatar/balking/App.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright (c) 2014 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.balking; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * @param args the command line arguments - not used + */ + public static void main(String... args) { + final WashingMachine washingMachine = new WashingMachine(); + ExecutorService executorService = Executors.newFixedThreadPool(3); + for (int i = 0; i < 3; i++) { + executorService.execute(washingMachine::wash); + } + executorService.shutdown(); + try { + executorService.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + LOGGER.error("ERROR: Waiting on executor service shutdown!"); + } + } + +} diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java new file mode 100644 index 000000000..fd4455e70 --- /dev/null +++ b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java @@ -0,0 +1,73 @@ +/** + * The MIT License + * Copyright (c) 2014 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.balking; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WashingMachine { + + private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class); + + private WashingMachineState washingMachineState; + + public WashingMachine() { + washingMachineState = WashingMachineState.ENABLED; + } + + public WashingMachineState getWashingMachineState() { + return washingMachineState; + } + + /** + * Method responsible for washing + * if the object is in appropriate state + */ + public void wash() { + synchronized (this) { + LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), getWashingMachineState()); + if (washingMachineState == WashingMachineState.WASHING) { + LOGGER.error("ERROR: Cannot wash if the machine has been already washing!"); + return; + } + washingMachineState = WashingMachineState.WASHING; + } + LOGGER.info("{}: Doing the washing", Thread.currentThread().getName()); + try { + Thread.sleep(50); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + endOfWashing(); + } + + /** + * Method responsible of ending the washing + * by changing machine state + */ + public synchronized void endOfWashing() { + washingMachineState = WashingMachineState.ENABLED; + LOGGER.info("{}: Washing completed.", Thread.currentThread().getId()); + } + +} diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java b/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java new file mode 100644 index 000000000..9d6cf875a --- /dev/null +++ b/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.balking; + +public enum WashingMachineState {ENABLED, WASHING} diff --git a/balking/src/test/java/com/iluwatar/balking/AppTest.java b/balking/src/test/java/com/iluwatar/balking/AppTest.java new file mode 100644 index 000000000..8b647e1a6 --- /dev/null +++ b/balking/src/test/java/com/iluwatar/balking/AppTest.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright (c) 2014 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.balking; + +public class AppTest { + @org.junit.Test + public void main() throws Exception { + String[] args = {}; + App.main(args); + } + +} \ No newline at end of file diff --git a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java new file mode 100644 index 000000000..2c7527676 --- /dev/null +++ b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright (c) 2014 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.balking; + +import org.junit.Test; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; + +public class WashingMachineTest { + + private volatile WashingMachineState machineStateGlobal; + + @Test + public void wash() throws Exception { + WashingMachine washingMachine = new WashingMachine(); + ExecutorService executorService = Executors.newFixedThreadPool(2); + executorService.execute(washingMachine::wash); + executorService.execute(() -> { + washingMachine.wash(); + machineStateGlobal = washingMachine.getWashingMachineState(); + }); + executorService.shutdown(); + try { + executorService.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + assertEquals(WashingMachineState.WASHING, machineStateGlobal); + } + + @Test + public void endOfWashing() throws Exception { + WashingMachine washingMachine = new WashingMachine(); + washingMachine.wash(); + assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState()); + } + +} \ No newline at end of file From bb4a1bdc05ac0cc5500c5dc40b4b6724d22f9b39 Mon Sep 17 00:00:00 2001 From: Katarzyna Rzepecka Date: Mon, 9 Jan 2017 22:54:20 +0100 Subject: [PATCH 203/492] Pom.xml files fixed. --- balking/pom.xml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/balking/pom.xml b/balking/pom.xml index e5b8f11f3..fe54815cb 100644 --- a/balking/pom.xml +++ b/balking/pom.xml @@ -26,21 +26,21 @@ - - java-design-patterns - com.iluwatar - 1.14.0-SNAPSHOT - - 4.0.0 + + java-design-patterns + com.iluwatar + 1.14.0-SNAPSHOT + + 4.0.0 - balking - - - junit - junit - test - - + balking + + + junit + junit + test + + \ No newline at end of file From cca4d5a670e3dbff8a64b8635d2604827211a38b Mon Sep 17 00:00:00 2001 From: Katarzyna Rzepecka Date: Mon, 13 Mar 2017 01:33:14 +0100 Subject: [PATCH 204/492] Update after changes from review. Additional improvements. --- balking/README.md | 6 +++++- balking/pom.xml | 2 +- .../main/java/com/iluwatar/balking/App.java | 18 +++++++++++++++--- .../com/iluwatar/balking/WashingMachine.java | 6 +++--- .../iluwatar/balking/WashingMachineState.java | 15 +++++++++++---- .../java/com/iluwatar/balking/AppTest.java | 15 +++++++++++---- .../iluwatar/balking/WashingMachineTest.java | 6 +++--- pom.xml | 1 + 8 files changed, 50 insertions(+), 19 deletions(-) diff --git a/balking/README.md b/balking/README.md index e5f8a6711..1ca7ccfb1 100644 --- a/balking/README.md +++ b/balking/README.md @@ -20,4 +20,8 @@ Use the Balking pattern when *you want to invoke an action on an object only when it is in a particular state *objects are generally only in a state that is prone to balking temporarily -but for an unknown amount of time \ No newline at end of file +but for an unknown amount of time + +## Related patterns +* Guarded Suspendion Pattern +* Double Checked Locking Pattern \ No newline at end of file diff --git a/balking/pom.xml b/balking/pom.xml index fe54815cb..ad066aee6 100644 --- a/balking/pom.xml +++ b/balking/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT 4.0.0 diff --git a/balking/src/main/java/com/iluwatar/balking/App.java b/balking/src/main/java/com/iluwatar/balking/App.java index 8fb0edcb0..47b10cd46 100644 --- a/balking/src/main/java/com/iluwatar/balking/App.java +++ b/balking/src/main/java/com/iluwatar/balking/App.java @@ -1,17 +1,17 @@ /** * The MIT License * Copyright (c) 2014 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 @@ -29,6 +29,18 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +/** + * In Balking Design Pattern if an object’s method is invoked when it is in an inappropriate state, + * then the method will return without doing anything. Objects that use this pattern are generally only in a + * state that is prone to balking temporarily but for an unknown amount of time + * + * In this example implementation WashingMachine is an object that has two states + * in which it can be: ENABLED and WASHING. If the machine is ENABLED + * the state is changed into WASHING that any other thread can't invoke this action on this and then do the job. + * On the other hand if it have been already washing and any other thread execute wash() + * it can't do that once again and returns doing nothing. + */ + public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java index fd4455e70..2167a0e52 100644 --- a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java +++ b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java @@ -1,17 +1,17 @@ /** * The MIT License * Copyright (c) 2014 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 diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java b/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java index 9d6cf875a..40a5b2f38 100644 --- a/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java +++ b/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java @@ -1,17 +1,17 @@ /** * The MIT License * Copyright (c) 2014 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 @@ -22,4 +22,11 @@ */ package com.iluwatar.balking; -public enum WashingMachineState {ENABLED, WASHING} +/** + * WashingMachineState enum describes in which state machine is, + * it can be enabled and ready to work as well as during washing + */ + +public enum WashingMachineState { + ENABLED, WASHING +} diff --git a/balking/src/test/java/com/iluwatar/balking/AppTest.java b/balking/src/test/java/com/iluwatar/balking/AppTest.java index 8b647e1a6..df104b901 100644 --- a/balking/src/test/java/com/iluwatar/balking/AppTest.java +++ b/balking/src/test/java/com/iluwatar/balking/AppTest.java @@ -1,17 +1,17 @@ /** * The MIT License * Copyright (c) 2014 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 @@ -20,10 +20,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + package com.iluwatar.balking; +import org.junit.Test; + +/** + * Application test + */ public class AppTest { - @org.junit.Test + + @Test public void main() throws Exception { String[] args = {}; App.main(args); diff --git a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java index 2c7527676..3dc87d64f 100644 --- a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java +++ b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java @@ -1,17 +1,17 @@ /** * The MIT License * Copyright (c) 2014 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 diff --git a/pom.xml b/pom.xml index d2ea715a7..925aea6ed 100644 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,7 @@ queue-load-leveling object-mother guarded-suspension + balking From 2c2d874ac89fdceda239e55ac26ce1470a543aae Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Mar 2017 10:00:13 +0100 Subject: [PATCH 205/492] Update App.java Correction of error detected by maven-pmd-plugin. --- tls/src/main/java/com/iluwatar/tls/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java index 80e87042c..bc67d0c2c 100644 --- a/tls/src/main/java/com/iluwatar/tls/App.java +++ b/tls/src/main/java/com/iluwatar/tls/App.java @@ -104,7 +104,7 @@ public class App { System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); } catch (Exception e) { - // no action here + System.out.println("Abnormal end of program. Program throws exception: "); } executor.shutdown(); } From f84c4c161120fa18ae2a1c854e61229df23b9aef Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Mar 2017 10:02:37 +0100 Subject: [PATCH 206/492] Update App.java Correction of correction ;-) --- tls/src/main/java/com/iluwatar/tls/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java index bc67d0c2c..634d36d26 100644 --- a/tls/src/main/java/com/iluwatar/tls/App.java +++ b/tls/src/main/java/com/iluwatar/tls/App.java @@ -104,7 +104,7 @@ public class App { System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); } catch (Exception e) { - System.out.println("Abnormal end of program. Program throws exception: "); + System.out.println("Abnormal end of program. Program throws exception: " + e); } executor.shutdown(); } From 09585c3874e9b8a3e59bb044f96baec1be0c07b7 Mon Sep 17 00:00:00 2001 From: Mudit Porwal Date: Wed, 22 Mar 2017 01:16:01 +0800 Subject: [PATCH 207/492] Removed AvoidStarImport Rule Added JavaDocType Rule --- .../abstractfactory/AbstractFactoryTest.java | 3 ++ .../aggregator/microservices/App.java | 3 ++ .../microservices/AggregatorTest.java | 11 +++--- .../microservice/InformationController.java | 3 ++ .../InformationControllerTest.java | 5 ++- .../microservice/InventoryController.java | 3 ++ .../microservice/InventoryControllerTest.java | 6 ++-- .../iluwatar/api/gateway/ImageClientImpl.java | 2 +- .../iluwatar/api/gateway/PriceClientImpl.java | 2 +- .../iluwatar/api/gateway/ApiGatewayTest.java | 9 +++-- .../microservice/ImageControllerTest.java | 3 ++ .../microservice/PriceControllerTest.java | 4 +++ .../async/method/invocation/AsyncResult.java | 2 +- checkstyle.xml | 15 ++++---- .../com/iluwatar/dao/CustomerSchemaSql.java | 9 +++-- .../java/com/iluwatar/dao/CustomerTest.java | 3 ++ .../java/com/iluwatar/datamapper/Student.java | 23 ++++++------ .../datamapper/StudentDataMapper.java | 3 ++ .../datamapper/StudentDataMapperImpl.java | 3 ++ .../com/iluwatar/datamapper/StudentTest.java | 10 ++++-- .../delegation/simple/PrinterController.java | 6 ++++ .../iluwatar/delegation/simple/AppTest.java | 4 ++- .../delegation/simple/DelegateTest.java | 15 +++++--- .../injection/utils/InMemoryAppender.java | 4 +++ .../doubledispatch/CollisionTest.java | 7 ++-- .../event/aggregator/EventEmitterTest.java | 18 +++++----- .../EventDoesNotExistException.java | 3 ++ .../iluwatar/event/asynchronous/IEvent.java | 4 +++ .../InvalidOperationException.java | 3 ++ .../LongRunningEventException.java | 3 ++ .../MaxNumOfEventsAllowedException.java | 3 ++ .../asynchronous/ThreadCompleteListener.java | 3 ++ .../com/iluwatar/eda/framework/Handler.java | 3 +- .../java/com/iluwatar/factorykit/Axe.java | 3 ++ .../java/com/iluwatar/factorykit/Bow.java | 3 ++ .../java/com/iluwatar/factorykit/Spear.java | 4 ++- .../java/com/iluwatar/factorykit/Sword.java | 4 ++- .../com/iluwatar/factorykit/app/AppTest.java | 3 ++ .../factorykit/factorykit/FactoryKitTest.java | 17 ++++++--- .../PropertiesFeatureToggleVersionTest.java | 16 +++++---- .../TieredFeatureToggleVersionTest.java | 11 +++--- .../featuretoggle/user/UserGroupTest.java | 9 +++-- .../lazy/DecoratingIterator.java | 7 ++-- .../iluwatar/fluentinterface/app/AppTest.java | 4 ++- .../controller/utils/InMemoryAppender.java | 3 ++ .../guarded/suspension/GuardedQueue.java | 7 +++- .../guarded/suspension/GuardedQueueTest.java | 5 ++- .../domain/LotteryTicketCheckResult.java | 9 +++-- .../hexagonal/domain/LotteryTicketTest.java | 3 ++ .../iluwatar/interpreter/ExpressionTest.java | 9 ++--- .../model/view/controller/GiantViewTest.java | 14 ++++---- .../src/main/java/com/iluwatar/monad/Sex.java | 3 ++ .../main/java/com/iluwatar/monad/User.java | 3 ++ .../test/java/com/iluwatar/monad/AppTest.java | 3 ++ .../java/com/iluwatar/monad/MonadTest.java | 3 ++ .../java/com/iluwatar/monostate/AppTest.java | 3 ++ .../test/java/com/iluwatar/mute/MuteTest.java | 25 +++++++------ .../test/java/com/iluwatar/mutex/AppTest.java | 5 ++- .../dom/app/homepage/HomePageService.java | 8 +++-- .../dom/app/homepage/HomePageViewModel.java | 9 +++-- .../dom/modules/simple/SimpleObject.java | 12 +++++-- .../dom/modules/simple/SimpleObjects.java | 10 ++++-- .../dom/modules/simple/SimpleObjectTest.java | 10 ++++-- .../dom/modules/simple/SimpleObjectsTest.java | 22 +++++++----- .../modules/simple/SimpleObjectCreate.java | 11 +++--- .../modules/simple/SimpleObjectsTearDown.java | 9 +++-- .../scenarios/RecreateSimpleObjects.java | 12 ++++--- .../bootstrap/SimpleAppSystemInitializer.java | 7 ++-- .../specglue/BootstrappingGlue.java | 3 ++ .../specglue/CatalogOfFixturesGlue.java | 3 ++ .../modules/simple/SimpleObjectGlue.java | 14 ++++---- .../integtests/tests/SimpleAppIntegTest.java | 4 ++- .../modules/simple/SimpleObjectIntegTest.java | 32 +++++++++++------ .../simple/SimpleObjectsIntegTest.java | 36 +++++++++++-------- .../java/com/iluwatar/objectmother/King.java | 9 +++-- .../java/com/iluwatar/objectmother/Queen.java | 7 ++-- .../com/iluwatar/objectmother/Royalty.java | 9 +++-- .../objectmother/RoyaltyObjectMother.java | 15 ++++---- .../test/RoyaltyObjectMotherTest.java | 15 ++++---- .../com/iluwatar/object/pool/ObjectPool.java | 2 +- .../iluwatar/observer/generic/Observer.java | 4 ++- .../observer/WeatherObserverTest.java | 10 +++--- .../observer/generic/ObserverTest.java | 10 +++--- .../observer/utils/InMemoryAppender.java | 3 ++ .../pageobject/AlbumListPageTest.java | 8 +++-- .../iluwatar/pageobject/AlbumPageTest.java | 7 ++-- .../iluwatar/pageobject/LoginPageTest.java | 7 ++-- .../com/iluwatar/poison/pill/Message.java | 3 ++ .../utils/InMemoryAppender.java | 3 ++ .../java/com/iluwatar/promise/Utility.java | 3 ++ .../java/com/iluwatar/property/Character.java | 3 ++ .../com/iluwatar/prototype/PrototypeTest.java | 15 ++++---- .../proxy/utils/InMemoryAppender.java | 4 +++ .../writer/lock/utils/InMemoryAppender.java | 3 ++ .../repository/PersonSpecifications.java | 3 ++ .../is/initialization/ClosableTest.java | 12 ++++--- .../java/com/iluwatar/semaphore/Fruit.java | 21 ++++++----- .../java/com/iluwatar/semaphore/AppTest.java | 5 ++- .../servicelayer/common/BaseDaoTest.java | 24 ++++++------- .../com/iluwatar/singleton/SingletonTest.java | 9 +++-- .../templatemethod/StealingMethodTest.java | 13 ++++--- .../com/iluwatar/threadpool/TaskTest.java | 12 +++---- .../java/com/iluwatar/twin/BallItemTest.java | 18 ++++++---- .../java/com/iluwatar/visitor/UnitTest.java | 14 ++++---- .../com/iluwatar/visitor/VisitorTest.java | 14 ++++---- 105 files changed, 577 insertions(+), 284 deletions(-) diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java index 82fd8acff..b6fca8b23 100644 --- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java +++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java @@ -28,6 +28,9 @@ import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +/** + * Test for abstract factory + */ public class AbstractFactoryTest { private App app = new App(); diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java index 2c14774d5..c43112c2e 100644 --- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java +++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java @@ -25,6 +25,9 @@ package com.iluwatar.aggregator.microservices; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +/** + * Spring Boot EntryPoint Class + */ @SpringBootApplication public class App { diff --git a/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java index f44aa2044..2955f6781 100644 --- a/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java +++ b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java @@ -22,15 +22,18 @@ */ package com.iluwatar.aggregator.microservices; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.when; - +/** + * Test Aggregation of domain objects + */ public class AggregatorTest { @InjectMocks @@ -64,4 +67,4 @@ public class AggregatorTest { assertEquals(inventories, testProduct.getProductInventories()); } -} \ No newline at end of file +} diff --git a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java index ff020585c..63b6fb9d5 100644 --- a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java +++ b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java @@ -26,6 +26,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +/** + * Controller providing endpoints to retrieve information about products + */ @RestController public class InformationController { diff --git a/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java b/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java index 12d59aee6..127dd3956 100644 --- a/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java +++ b/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java @@ -25,6 +25,9 @@ package com.iluwatar.information.microservice; import org.junit.Assert; import org.junit.Test; +/** + * Test for Information Rest Controller + */ public class InformationControllerTest { @Test @@ -36,4 +39,4 @@ public class InformationControllerTest { Assert.assertEquals("The Product Title.", title); } -} \ No newline at end of file +} diff --git a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java index 987ab0b3d..e6b2eca80 100644 --- a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java +++ b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java @@ -26,6 +26,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +/** + * Controller providing endpoints to retrieve product inventories + */ @RestController public class InventoryController { diff --git a/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java b/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java index b461461d3..b04370fba 100644 --- a/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java +++ b/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java @@ -25,8 +25,10 @@ package com.iluwatar.inventory.microservice; import org.junit.Assert; import org.junit.Test; +/** + * Test Inventory Rest Controller + */ public class InventoryControllerTest { - @Test public void testGetProductInventories() throws Exception { InventoryController inventoryController = new InventoryController(); @@ -35,4 +37,4 @@ public class InventoryControllerTest { Assert.assertEquals(5, numberOfInventories); } -} \ No newline at end of file +} diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java index 10f8625c5..ebabfe839 100644 --- a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java +++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java @@ -35,7 +35,7 @@ import java.io.IOException; * An adapter to communicate with the Image microservice */ @Component -public class ImageClientImpl implements ImageClient{ +public class ImageClientImpl implements ImageClient { /** * Makes a simple HTTP Get request to the Image microservice * @return The path to the image diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java index aa2686845..87f44761c 100644 --- a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java +++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java @@ -35,7 +35,7 @@ import java.io.IOException; * An adapter to communicate with the Price microservice */ @Component -public class PriceClientImpl implements PriceClient{ +public class PriceClientImpl implements PriceClient { /** * Makes a simple HTTP Get request to the Price microservice * @return The price of the product diff --git a/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java b/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java index fe8e76db4..6a79e5d00 100644 --- a/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java +++ b/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java @@ -22,15 +22,18 @@ */ package com.iluwatar.api.gateway; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.when; - +/** + * Test API Gateway Pattern + */ public class ApiGatewayTest { @InjectMocks diff --git a/api-gateway/image-microservice/src/test/java/com/iluwatar/image/microservice/ImageControllerTest.java b/api-gateway/image-microservice/src/test/java/com/iluwatar/image/microservice/ImageControllerTest.java index 3f4154b58..1b934014a 100644 --- a/api-gateway/image-microservice/src/test/java/com/iluwatar/image/microservice/ImageControllerTest.java +++ b/api-gateway/image-microservice/src/test/java/com/iluwatar/image/microservice/ImageControllerTest.java @@ -25,6 +25,9 @@ package com.iluwatar.image.microservice; import org.junit.Assert; import org.junit.Test; +/** + * Test for Image Rest Controller + */ public class ImageControllerTest { @Test public void testGetImagePath() { diff --git a/api-gateway/price-microservice/src/test/java/com/iluwatar/price/microservice/PriceControllerTest.java b/api-gateway/price-microservice/src/test/java/com/iluwatar/price/microservice/PriceControllerTest.java index 634a60b04..b1fe66d42 100644 --- a/api-gateway/price-microservice/src/test/java/com/iluwatar/price/microservice/PriceControllerTest.java +++ b/api-gateway/price-microservice/src/test/java/com/iluwatar/price/microservice/PriceControllerTest.java @@ -25,6 +25,10 @@ package com.iluwatar.price.microservice; import org.junit.Assert; import org.junit.Test; + +/** + * Test for Price Rest Controller + */ public class PriceControllerTest { @Test public void testgetPrice() { diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java index 3fa99cc27..f7fd9ab61 100644 --- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java +++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java @@ -25,8 +25,8 @@ package com.iluwatar.async.method.invocation; import java.util.concurrent.ExecutionException; /** - * * AsyncResult interface + * @param parameter returned when getValue is invoked */ public interface AsyncResult { diff --git a/checkstyle.xml b/checkstyle.xml index 46b1aa354..37db7e711 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -32,10 +32,10 @@ Source = https://github.com/checkstyle/checkstyle/tree/master/src/main/resources Checkstyle configurartion that checks the Google coding conventions from: - + - Google Java Style https://google-styleguide.googlecode.com/svn-history/r130/trunk/javaguide.html - + Checkstyle is very configurable. Be sure to read the documentation at http://checkstyle.sf.net (or in your downloaded distribution). @@ -44,12 +44,12 @@ To completely disable a check, just comment it out or delete it from the file. Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov. - + --> - + @@ -77,7 +77,6 @@ - @@ -120,7 +119,7 @@ - + @@ -185,6 +184,10 @@ + + + + find(int studentId); diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java index 7ecd9e7f8..685a439ac 100644 --- a/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java +++ b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java @@ -22,6 +22,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +/** + * Implementation of Actions on Students Data + */ public final class StudentDataMapperImpl implements StudentDataMapper { /* Note: Normally this would be in the form of an actual database */ diff --git a/data-mapper/src/test/java/com/iluwatar/datamapper/StudentTest.java b/data-mapper/src/test/java/com/iluwatar/datamapper/StudentTest.java index a3c0e46c1..ec35b21de 100644 --- a/data-mapper/src/test/java/com/iluwatar/datamapper/StudentTest.java +++ b/data-mapper/src/test/java/com/iluwatar/datamapper/StudentTest.java @@ -18,17 +18,21 @@ */ package com.iluwatar.datamapper; -import org.junit.Test; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +/** + * Tests {@link Student}. + */ public final class StudentTest { @Test /** * This API tests the equality behaviour of Student object * Object Equality should work as per logic defined in equals method - * + * * @throws Exception if any execution error during test */ public void testEquality() throws Exception { diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java index 86b841a28..c54f611ee 100644 --- a/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java +++ b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java @@ -22,6 +22,12 @@ */ package com.iluwatar.delegation.simple; +/** + * Delegator Class to delegate the implementation of the Printer. + * This ensures two things: + * - when the actual implementation of the Printer class changes the delegation will still be operational + * - the actual benefit is observed when there are more than one implementors and they share a delegation control + */ public class PrinterController implements Printer { private final Printer printer; diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java index a8fae59e3..434d94baa 100644 --- a/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java +++ b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java @@ -23,7 +23,9 @@ package com.iluwatar.delegation.simple; import org.junit.Test; - +/** + * Application Test Entry + */ public class AppTest { @Test diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java index b27539def..fd99a30dd 100644 --- a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java +++ b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java @@ -22,22 +22,24 @@ */ package com.iluwatar.delegation.simple; +import static org.junit.Assert.assertEquals; + import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.AppenderBase; import com.iluwatar.delegation.simple.printers.CanonPrinter; import com.iluwatar.delegation.simple.printers.EpsonPrinter; import com.iluwatar.delegation.simple.printers.HpPrinter; +import java.util.LinkedList; +import java.util.List; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.LoggerFactory; -import java.util.LinkedList; -import java.util.List; - -import static org.junit.Assert.assertEquals; - +/** + * Test for Delegation Pattern + */ public class DelegateTest { private InMemoryAppender appender; @@ -78,6 +80,9 @@ public class DelegateTest { assertEquals("Epson Printer : Test Message Printed", appender.getLastMessage()); } + /** + * Logging Appender + */ private class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java index 76d1cc1dd..b79bf3d40 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/utils/InMemoryAppender.java @@ -30,6 +30,10 @@ import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.List; + +/** + * InMemory Log Appender Util. + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java index 5e9a001e7..3dc32905a 100644 --- a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java +++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java @@ -22,13 +22,14 @@ */ package com.iluwatar.doubledispatch; -import java.util.Objects; - import static org.junit.Assert.assertEquals; +import java.util.Objects; + /** * Date: 12/10/15 - 8:37 PM - * + * Test for Collision + * @param Type of GameObject * @author Jeroen Meulemeester */ public abstract class CollisionTest { diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java index ba7ecbc2d..a67272789 100644 --- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java +++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java @@ -22,22 +22,22 @@ */ package com.iluwatar.event.aggregator; -import org.junit.Test; - -import java.util.Objects; -import java.util.function.Function; -import java.util.function.Supplier; - import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; + +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Supplier; +import org.junit.Test; /** * Date: 12/12/15 - 10:58 PM - * + * Tests for Event Emitter + * @param Type of Event Emitter * @author Jeroen Meulemeester */ public abstract class EventEmitterTest { @@ -115,7 +115,7 @@ public abstract class EventEmitterTest { // The observers should not have received any additional events after the week verifyNoMoreInteractions(observers); } - + /** * Go over every day of the month, and check if the event is emitted on the given day. Use an * event emitter without a default observer diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java index 85edaa815..e7a5e75b6 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/EventDoesNotExistException.java @@ -16,6 +16,9 @@ */ package com.iluwatar.event.asynchronous; +/** + * Custom Exception Class for Non Existent Event + */ public class EventDoesNotExistException extends Exception { private static final long serialVersionUID = -3398463738273811509L; diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java index 296a312a3..bfb5d4f04 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/IEvent.java @@ -16,6 +16,10 @@ */ package com.iluwatar.event.asynchronous; +/** + * Events that fulfill the start stop and list out current status behaviour + * follow this interface + */ public interface IEvent { void start(); diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java index 3c930d935..7ca5cfc9a 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/InvalidOperationException.java @@ -16,6 +16,9 @@ */ package com.iluwatar.event.asynchronous; +/** + * Type of Exception raised when the Operation being invoked is Invalid + */ public class InvalidOperationException extends Exception { private static final long serialVersionUID = -6191545255213410803L; diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java index 7c9091a15..b11f1a335 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/LongRunningEventException.java @@ -16,6 +16,9 @@ */ package com.iluwatar.event.asynchronous; +/** + * Type of Exception raised when the Operation being invoked is Long Running + */ public class LongRunningEventException extends Exception { private static final long serialVersionUID = -483423544320148809L; diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java index 2b8f2221c..17b46fd88 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/MaxNumOfEventsAllowedException.java @@ -16,6 +16,9 @@ */ package com.iluwatar.event.asynchronous; +/** + * Type of Exception raised when the max number of allowed events is exceeded + */ public class MaxNumOfEventsAllowedException extends Exception { private static final long serialVersionUID = -8430876973516292695L; diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java index be4ecf93b..7a37f7614 100644 --- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java +++ b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/ThreadCompleteListener.java @@ -16,6 +16,9 @@ */ package com.iluwatar.event.asynchronous; +/** + * Interface with listener behaviour related to Thread Completion. + */ public interface ThreadCompleteListener { void completedEventHandler(final int eventId); } diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java index e2b58cd49..3208e1edf 100644 --- a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java +++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java @@ -25,6 +25,7 @@ package com.iluwatar.eda.framework; /** * This interface can be implemented to handle different types of messages. * Every handler is responsible for a single of type message + * @param Handler can handle events of type E */ public interface Handler { @@ -35,4 +36,4 @@ public interface Handler { * @param event the {@link Event} object to be handled. */ void onEvent(E event); -} \ No newline at end of file +} diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java index 96ce73a35..429728cbc 100644 --- a/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java @@ -22,6 +22,9 @@ */ package com.iluwatar.factorykit; +/** + * Class representing Axe + */ public class Axe implements Weapon { @Override public String toString() { diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java index b9b2708c9..c655c3be8 100644 --- a/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java @@ -22,6 +22,9 @@ */ package com.iluwatar.factorykit; +/** + * Class representing Bows + */ public class Bow implements Weapon { @Override public String toString() { diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java index 080007093..15ff8b246 100644 --- a/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java @@ -21,7 +21,9 @@ * THE SOFTWARE. */ package com.iluwatar.factorykit; - +/** + * Class representing Spear + */ public class Spear implements Weapon { @Override public String toString() { diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java index 504ddb397..42ab53799 100644 --- a/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java +++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java @@ -21,7 +21,9 @@ * THE SOFTWARE. */ package com.iluwatar.factorykit; - +/** + * Class representing Swords + */ public class Sword implements Weapon { @Override public String toString() { diff --git a/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java index add378296..4d8691ef0 100644 --- a/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java +++ b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java @@ -25,6 +25,9 @@ package com.iluwatar.factorykit.app; import com.iluwatar.factorykit.App; import org.junit.Test; +/** + * Application Test Entrypoint + */ public class AppTest { @Test diff --git a/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java b/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java index da39caa8f..3f732546d 100644 --- a/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java +++ b/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java @@ -1,4 +1,4 @@ -/** + /** * The MIT License * Copyright (c) 2014-2016 Ilkka Seppälä * @@ -22,12 +22,19 @@ */ package com.iluwatar.factorykit.factorykit; -import com.iluwatar.factorykit.*; -import org.junit.Before; -import org.junit.Test; - import static org.junit.Assert.assertTrue; +import com.iluwatar.factorykit.Axe; +import com.iluwatar.factorykit.Spear; +import com.iluwatar.factorykit.Sword; +import com.iluwatar.factorykit.Weapon; +import com.iluwatar.factorykit.WeaponFactory; +import com.iluwatar.factorykit.WeaponType; +import org.junit.Before; +import org.junit.Test; +/** + * Test Factory Kit Pattern + */ public class FactoryKitTest { private WeaponFactory factory; diff --git a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersionTest.java b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersionTest.java index def53b97c..846b46bcf 100644 --- a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersionTest.java +++ b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersionTest.java @@ -23,16 +23,18 @@ package com.iluwatar.featuretoggle.pattern.propertiesversion; -import com.iluwatar.featuretoggle.pattern.Service; -import com.iluwatar.featuretoggle.user.User; -import org.junit.Test; - -import java.util.Properties; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import com.iluwatar.featuretoggle.pattern.Service; +import com.iluwatar.featuretoggle.user.User; +import java.util.Properties; +import org.junit.Test; + +/** + * Test Properties Toggle + */ public class PropertiesFeatureToggleVersionTest { @Test(expected = IllegalArgumentException.class) @@ -66,4 +68,4 @@ public class PropertiesFeatureToggleVersionTest { final String welcomeMessage = service.getWelcomeMessage(new User("Jamie No Code")); assertEquals("Welcome to the application.", welcomeMessage); } -} \ No newline at end of file +} diff --git a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersionTest.java b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersionTest.java index 6c33b260c..3966032d5 100644 --- a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersionTest.java +++ b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersionTest.java @@ -22,15 +22,18 @@ */ package com.iluwatar.featuretoggle.pattern.tieredversion; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import com.iluwatar.featuretoggle.pattern.Service; import com.iluwatar.featuretoggle.user.User; import com.iluwatar.featuretoggle.user.UserGroup; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - +/** + * Test Tiered Feature Toggle + */ public class TieredFeatureToggleVersionTest { final User paidUser = new User("Jamie Coder"); @@ -61,4 +64,4 @@ public class TieredFeatureToggleVersionTest { public void testIsEnhancedAlwaysTrueAsTiered() throws Exception { assertTrue(service.isEnhanced()); } -} \ No newline at end of file +} diff --git a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/user/UserGroupTest.java b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/user/UserGroupTest.java index c6ff30855..b2c6e5859 100644 --- a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/user/UserGroupTest.java +++ b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/user/UserGroupTest.java @@ -22,11 +22,14 @@ */ package com.iluwatar.featuretoggle.user; -import org.junit.Test; - import static junit.framework.TestCase.assertFalse; import static org.junit.Assert.assertTrue; +import org.junit.Test; + +/** + * Test User Group specific feature + */ public class UserGroupTest { @Test @@ -56,4 +59,4 @@ public class UserGroupTest { UserGroup.addUserToPaidGroup(user); UserGroup.addUserToFreeGroup(user); } -} \ No newline at end of file +} diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java index 54d367c20..389904bff 100644 --- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java @@ -27,6 +27,7 @@ import java.util.Iterator; /** * This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not * support consecutive hasNext() calls. + * @param Iterable Collection of Elements of Type E */ public abstract class DecoratingIterator implements Iterator { @@ -43,7 +44,7 @@ public abstract class DecoratingIterator implements Iterator { /** * Precomputes and saves the next element of the Iterable. null is considered as end of data. - * + * * @return true if a next element is available */ @Override @@ -54,7 +55,7 @@ public abstract class DecoratingIterator implements Iterator { /** * Returns the next element of the Iterable. - * + * * @return the next element of the Iterable, or null if not present. */ @Override @@ -71,7 +72,7 @@ public abstract class DecoratingIterator implements Iterator { /** * Computes the next object of the Iterable. Can be implemented to realize custom behaviour for an * iteration process. null is considered as end of data. - * + * * @return the next element of the Iterable. */ public abstract E computeNext(); diff --git a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java index 6d6420d55..11740bf1a 100644 --- a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java +++ b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java @@ -23,7 +23,9 @@ package com.iluwatar.fluentinterface.app; import org.junit.Test; - +/** + * Application Test Entry + */ public class AppTest { @Test diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java b/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java index 62a234d0d..2e6f26c0c 100644 --- a/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java +++ b/front-controller/src/test/java/com/iluwatar/front/controller/utils/InMemoryAppender.java @@ -30,6 +30,9 @@ import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.List; +/** + * InMemory Log Appender Util. + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java index 89b330bfb..bf6142dd9 100644 --- a/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java +++ b/guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java @@ -28,7 +28,12 @@ import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.Queue; - +/** + * Guarded Queue is an implementation for Guarded Suspension Pattern + * Guarded suspension pattern is used to handle a situation when you want to execute a method + * on an object which is not in a proper state. + * @see http://java-design-patterns.com/patterns/guarded-suspension/ + */ public class GuardedQueue { private static final Logger LOGGER = LoggerFactory.getLogger(GuardedQueue.class); private final Queue sourceList; diff --git a/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java index 41eaccd49..5a741d399 100644 --- a/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java +++ b/guarded-suspension/src/test/java/com/iluwatar/guarded/suspension/GuardedQueueTest.java @@ -29,6 +29,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +/** + * Test for Guarded Queue + */ public class GuardedQueueTest { private volatile Integer value; @@ -55,4 +58,4 @@ public class GuardedQueueTest { } -} \ No newline at end of file +} diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketCheckResult.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketCheckResult.java index babbd6d03..a5b455354 100644 --- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketCheckResult.java +++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketCheckResult.java @@ -23,12 +23,15 @@ package com.iluwatar.hexagonal.domain; /** - * + * * Represents lottery ticket check result. * */ public class LotteryTicketCheckResult { + /** + * Enumeration of Type of Outcomes of a Lottery + */ public enum CheckResult { WIN_PRIZE, NO_PRIZE, TICKET_NOT_SUBMITTED } private final CheckResult checkResult; @@ -41,7 +44,7 @@ public class LotteryTicketCheckResult { checkResult = result; prizeAmount = 0; } - + /** * Constructor. */ @@ -56,7 +59,7 @@ public class LotteryTicketCheckResult { public CheckResult getResult() { return checkResult; } - + /** * @return prize amount */ diff --git a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java index 8aaa83681..a83f9033c 100644 --- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java +++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTicketTest.java @@ -30,6 +30,9 @@ import java.util.HashSet; import org.junit.Test; +/** + * Test Lottery Tickets for equality + */ public class LotteryTicketTest { @Test diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java index 95a65e82c..2d444373c 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java @@ -22,18 +22,19 @@ */ package com.iluwatar.interpreter; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import org.junit.Test; /** * Date: 12/14/15 - 11:48 AM * + * Test Case for Expressions + * @param Type of Expression * @author Jeroen Meulemeester */ public abstract class ExpressionTest { diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java index ba72fea1a..ec0aabd15 100644 --- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java +++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java @@ -22,20 +22,19 @@ */ package com.iluwatar.model.view.controller; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + 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.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.LoggerFactory; -import java.util.LinkedList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - /** * Date: 12/20/15 - 2:04 PM * @@ -70,6 +69,9 @@ public class GiantViewTest { assertEquals(1, appender.getLogSize()); } + /** + * Logging Appender Implementation + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/monad/src/main/java/com/iluwatar/monad/Sex.java b/monad/src/main/java/com/iluwatar/monad/Sex.java index 3cbe22971..6c6d6eff6 100644 --- a/monad/src/main/java/com/iluwatar/monad/Sex.java +++ b/monad/src/main/java/com/iluwatar/monad/Sex.java @@ -22,6 +22,9 @@ */ package com.iluwatar.monad; +/** + * Enumeration of Types of Sex + */ public enum Sex { MALE, FEMALE } diff --git a/monad/src/main/java/com/iluwatar/monad/User.java b/monad/src/main/java/com/iluwatar/monad/User.java index 53cf759cf..406407fea 100644 --- a/monad/src/main/java/com/iluwatar/monad/User.java +++ b/monad/src/main/java/com/iluwatar/monad/User.java @@ -22,6 +22,9 @@ */ package com.iluwatar.monad; +/** + * User Definition + */ public class User { private String name; diff --git a/monad/src/test/java/com/iluwatar/monad/AppTest.java b/monad/src/test/java/com/iluwatar/monad/AppTest.java index f661ee1c6..69464ff87 100644 --- a/monad/src/test/java/com/iluwatar/monad/AppTest.java +++ b/monad/src/test/java/com/iluwatar/monad/AppTest.java @@ -24,6 +24,9 @@ package com.iluwatar.monad; import org.junit.Test; +/** + * Application Test + */ public class AppTest { @Test diff --git a/monad/src/test/java/com/iluwatar/monad/MonadTest.java b/monad/src/test/java/com/iluwatar/monad/MonadTest.java index 2676e6e80..a34243978 100644 --- a/monad/src/test/java/com/iluwatar/monad/MonadTest.java +++ b/monad/src/test/java/com/iluwatar/monad/MonadTest.java @@ -30,6 +30,9 @@ import org.junit.rules.ExpectedException; import java.util.Objects; +/** + * Test for Monad Pattern + */ public class MonadTest { @Rule diff --git a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java index 301beea3e..3e88b3bf2 100644 --- a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java +++ b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java @@ -24,6 +24,9 @@ package com.iluwatar.monostate; import org.junit.Test; +/** + * Application Test Entry + */ public class AppTest { @Test diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java index 698395cc2..7e1d2e1af 100644 --- a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java +++ b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java @@ -35,47 +35,50 @@ import org.junit.rules.ExpectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Test for the mute-idiom pattern + */ public class MuteTest { private static final Logger LOGGER = LoggerFactory.getLogger(MuteTest.class); private static final String MESSAGE = "should not occur"; - + @Rule public ExpectedException exception = ExpectedException.none(); - + @Test public void muteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() { Mute.mute(() -> methodNotThrowingAnyException()); } - + @Test public void muteShouldRethrowUnexpectedExceptionAsAssertionError() throws Exception { exception.expect(AssertionError.class); exception.expectMessage(MESSAGE); - + Mute.mute(() -> methodThrowingException()); } - + @Test public void loggedMuteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() { Mute.loggedMute(() -> methodNotThrowingAnyException()); } - + @Test public void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); System.setErr(new PrintStream(stream)); - + Mute.loggedMute(() -> methodThrowingException()); - + assertTrue(new String(stream.toByteArray()).contains(MESSAGE)); } - - + + private void methodNotThrowingAnyException() { LOGGER.info("Executed successfully"); } - + private void methodThrowingException() throws Exception { throw new Exception(MESSAGE); } diff --git a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java index dfc0de124..f224a56f5 100644 --- a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java +++ b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java @@ -25,10 +25,13 @@ package com.iluwatar.mutex; import org.junit.Test; import java.io.IOException; +/** + * Application Test Entrypoint + */ public class AppTest{ @Test public void test() throws IOException { String[] args = {}; App.main(args); } -} \ No newline at end of file +} diff --git a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java index 162cd3bb4..30469ba8e 100644 --- a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java +++ b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -21,6 +21,10 @@ import org.apache.isis.applib.annotation.HomePage; import org.apache.isis.applib.annotation.NatureOfService; import org.apache.isis.applib.annotation.SemanticsOf; +/** + * HomePage Domain Service + * @see HomePageViewModel linked view to HomePage + */ @DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY) public class HomePageService { diff --git a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.java b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.java index f367a39fd..dfb499f0f 100644 --- a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.java +++ b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -21,6 +21,11 @@ import org.apache.isis.applib.annotation.ViewModel; import domainapp.dom.modules.simple.SimpleObject; import domainapp.dom.modules.simple.SimpleObjects; +/** + * Model linked to the HomePage + * The underlying layout is specified by json + * @see HomePageService - Service Linked to the HomePage + */ @ViewModel public class HomePageViewModel { diff --git a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java index bbbd54b00..c7972ab84 100644 --- a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java +++ b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -33,6 +33,9 @@ import org.apache.isis.applib.services.eventbus.ActionDomainEvent; import org.apache.isis.applib.services.i18n.TranslatableString; import org.apache.isis.applib.util.ObjectContracts; +/** + * Definition of a Simple Object + */ @javax.jdo.annotations.PersistenceCapable(identityType = IdentityType.DATASTORE, schema = "simple", table = "SimpleObject") @javax.jdo.annotations.DatastoreIdentity( @@ -53,7 +56,7 @@ public class SimpleObject implements Comparable { // region > name (property) private String name; - + // region > identificatiom public TranslatableString title() { return TranslatableString.tr("Object: {name}", "name", getName()); @@ -74,6 +77,9 @@ public class SimpleObject implements Comparable { // region > updateName (action) + /** + * Event used to update the Name in the Domain + */ public static class UpdateNameDomainEvent extends ActionDomainEvent { public UpdateNameDomainEvent(final SimpleObject source, final Identifier identifier, final Object... arguments) { diff --git a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java index 5ebad0159..249fbb1f0 100644 --- a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java +++ b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -30,6 +30,9 @@ import org.apache.isis.applib.query.QueryDefault; import org.apache.isis.applib.services.eventbus.ActionDomainEvent; import org.apache.isis.applib.services.i18n.TranslatableString; +/** + * Domain Service for Simple Objects + */ @DomainService(repositoryFor = SimpleObject.class) @DomainServiceLayout(menuOrder = "10") public class SimpleObjects { @@ -69,6 +72,9 @@ public class SimpleObjects { // endregion + /** + * Create Domain Event on SimpleObjects + */ // region > create (action) public static class CreateDomainEvent extends ActionDomainEvent { public CreateDomainEvent(final SimpleObjects source, final Identifier identifier, diff --git a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java index fc62239c2..d80d0786a 100644 --- a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java +++ b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectTest.java @@ -14,11 +14,14 @@ */ package domainapp.dom.modules.simple; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Before; import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; - +/** + * Test for SimpleObject + */ public class SimpleObjectTest { SimpleObject simpleObject; @@ -28,6 +31,9 @@ public class SimpleObjectTest { simpleObject = new SimpleObject(); } + /** + * Test for Names for SimpleObjects + */ public static class Name extends SimpleObjectTest { @Test diff --git a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java index 47cad61b8..91fe3d715 100644 --- a/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java +++ b/naked-objects/dom/src/test/java/domainapp/dom/modules/simple/SimpleObjectsTest.java @@ -14,10 +14,13 @@ */ package domainapp.dom.modules.simple; -import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import com.google.common.collect.Lists; - +import java.util.List; +import org.apache.isis.applib.DomainObjectContainer; +import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2; +import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode; import org.jmock.Expectations; import org.jmock.Sequence; import org.jmock.auto.Mock; @@ -25,12 +28,9 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.apache.isis.applib.DomainObjectContainer; -import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2; -import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode; - -import static org.assertj.core.api.Assertions.assertThat; - +/** + * Test for SimpleObjects + */ public class SimpleObjectsTest { @Rule @@ -47,6 +47,9 @@ public class SimpleObjectsTest { simpleObjects.container = mockContainer; } + /** + * Test Creation of Simple Objects + */ public static class Create extends SimpleObjectsTest { @Test @@ -77,6 +80,9 @@ public class SimpleObjectsTest { } + /** + * Test Listing of Simple Objects + */ public static class ListAll extends SimpleObjectsTest { @Test diff --git a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java index f0617fea2..58b656a98 100644 --- a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java +++ b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -20,6 +20,9 @@ import org.apache.isis.applib.fixturescripts.FixtureScript; import domainapp.dom.modules.simple.SimpleObject; import domainapp.dom.modules.simple.SimpleObjects; +/** + * Fixture to create a simple object + */ public class SimpleObjectCreate extends FixtureScript { // endregion @@ -45,7 +48,7 @@ public class SimpleObjectCreate extends FixtureScript { this.name = name; return this; } - + /** * The created simple object (output). */ @@ -65,5 +68,5 @@ public class SimpleObjectCreate extends FixtureScript { // also make available to UI ec.addResult(this, simpleObject); } - + } diff --git a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectsTearDown.java b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectsTearDown.java index 7000bf4c0..c0319d953 100644 --- a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectsTearDown.java +++ b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectsTearDown.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -18,6 +18,9 @@ package domainapp.fixture.modules.simple; import org.apache.isis.applib.fixturescripts.FixtureScript; import org.apache.isis.applib.services.jdosupport.IsisJdoSupport; +/** + * TearDown/Cleanup for SimpleObjects + */ public class SimpleObjectsTearDown extends FixtureScript { @javax.inject.Inject @@ -27,5 +30,5 @@ public class SimpleObjectsTearDown extends FixtureScript { protected void execute(ExecutionContext executionContext) { isisJdoSupport.executeUpdate("delete from \"simple\".\"SimpleObject\""); } - + } diff --git a/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java b/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java index 62ad0405a..be891158a 100644 --- a/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java +++ b/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -27,6 +27,10 @@ import domainapp.dom.modules.simple.SimpleObject; import domainapp.fixture.modules.simple.SimpleObjectCreate; import domainapp.fixture.modules.simple.SimpleObjectsTearDown; + +/** + * Create a bunch of simple Objects + */ public class RecreateSimpleObjects extends FixtureScript { public final List names = Collections.unmodifiableList(Arrays.asList("Foo", "Bar", "Baz", @@ -43,7 +47,7 @@ public class RecreateSimpleObjects extends FixtureScript { public RecreateSimpleObjects() { withDiscoverability(Discoverability.DISCOVERABLE); } - + /** * The number of objects to create, up to 10; optional, defaults to 3. */ @@ -55,7 +59,7 @@ public class RecreateSimpleObjects extends FixtureScript { this.number = number; return this; } - + /** * The simpleobjects created by this fixture (output). */ diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java b/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java index b7c76d0ed..3ac5a1d75 100644 --- a/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java +++ b/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java @@ -4,9 +4,9 @@ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under @@ -19,6 +19,9 @@ import org.apache.isis.core.integtestsupport.IsisSystemForTest; import org.apache.isis.objectstore.jdo.datanucleus.DataNucleusPersistenceMechanismInstaller; import org.apache.isis.objectstore.jdo.datanucleus.IsisConfigurationForJdoIntegTests; +/** + * Initializer for the Simple App + */ public final class SimpleAppSystemInitializer { private SimpleAppSystemInitializer() { diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/BootstrappingGlue.java b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/BootstrappingGlue.java index 190e1f5bb..e41399fdd 100644 --- a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/BootstrappingGlue.java +++ b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/BootstrappingGlue.java @@ -21,6 +21,9 @@ import cucumber.api.java.After; import cucumber.api.java.Before; import domainapp.integtests.bootstrap.SimpleAppSystemInitializer; +/** + * BootStrapping IntegrationTesting Before and After Steps + */ public class BootstrappingGlue extends CukeGlueAbstract { @Before(value = {"@integration"}, order = 100) diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java index 2fcb7cca7..7a75a0381 100644 --- a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java +++ b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/CatalogOfFixturesGlue.java @@ -19,6 +19,9 @@ import org.apache.isis.core.specsupport.specs.CukeGlueAbstract; import cucumber.api.java.Before; import domainapp.fixture.scenarios.RecreateSimpleObjects; +/** + * Test Execution to append a fixture of SimpleObjects + */ public class CatalogOfFixturesGlue extends CukeGlueAbstract { @Before(value = {"@integration", "@SimpleObjectsFixture"}, order = 20000) diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java index 2ea375b4a..b7af9f052 100644 --- a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java +++ b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java @@ -14,18 +14,20 @@ */ package domainapp.integtests.specglue.modules.simple; -import java.util.List; -import java.util.UUID; - -import org.apache.isis.core.specsupport.specs.CukeGlueAbstract; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; import cucumber.api.java.en.Given; import cucumber.api.java.en.When; import domainapp.dom.modules.simple.SimpleObject; import domainapp.dom.modules.simple.SimpleObjects; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import java.util.List; +import java.util.UUID; +import org.apache.isis.core.specsupport.specs.CukeGlueAbstract; +/** + * Test Simple Object Operations + */ public class SimpleObjectGlue extends CukeGlueAbstract { @Given("^there are.* (\\d+) simple objects$") diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java index 7a7ad91b2..66deaeb84 100644 --- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java +++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java @@ -25,6 +25,9 @@ import org.apache.isis.core.integtestsupport.scenarios.ScenarioExecutionForInteg import domainapp.integtests.bootstrap.SimpleAppSystemInitializer; +/** + * SimpleApp Integration Tests will implement this Abstract Class. + */ public abstract class SimpleAppIntegTest extends IntegrationTestAbstract { @BeforeClass @@ -35,5 +38,4 @@ public abstract class SimpleAppIntegTest extends IntegrationTestAbstract { // instantiating will install onto ThreadLocal new ScenarioExecutionForIntegration(); } - } diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java index 872aff7a3..f2cbb1723 100644 --- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java +++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java @@ -18,21 +18,22 @@ */ package domainapp.integtests.tests.modules.simple; -import javax.inject.Inject; - -import org.junit.Before; -import org.junit.Test; - -import org.apache.isis.applib.DomainObjectContainer; -import org.apache.isis.applib.fixturescripts.FixtureScripts; -import org.apache.isis.applib.services.wrapper.DisabledException; -import org.apache.isis.applib.services.wrapper.InvalidException; +import static org.assertj.core.api.Assertions.assertThat; import domainapp.dom.modules.simple.SimpleObject; import domainapp.fixture.scenarios.RecreateSimpleObjects; import domainapp.integtests.tests.SimpleAppIntegTest; -import static org.assertj.core.api.Assertions.assertThat; +import javax.inject.Inject; +import org.apache.isis.applib.DomainObjectContainer; +import org.apache.isis.applib.fixturescripts.FixtureScripts; +import org.apache.isis.applib.services.wrapper.DisabledException; +import org.apache.isis.applib.services.wrapper.InvalidException; +import org.junit.Before; +import org.junit.Test; +/** + * Test Fixtures with Simple Objects + */ public class SimpleObjectIntegTest extends SimpleAppIntegTest { @Inject @@ -54,6 +55,9 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest { simpleObjectWrapped = wrap(simpleObjectPojo); } + /** + * Test Object Name accessibility + */ public static class Name extends SimpleObjectIntegTest { @Test @@ -75,6 +79,9 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest { } } + /** + * Test Validation of SimpleObject Names + */ public static class UpdateName extends SimpleObjectIntegTest { @Test @@ -99,6 +106,9 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest { } } + /** + * Test ContainerTitle generation based on SimpleObject Name + */ public static class Title extends SimpleObjectIntegTest { @Inject @@ -117,4 +127,4 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest { assertThat(title).isEqualTo("Object: " + name); } } -} \ No newline at end of file +} diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java index 332213542..d57454dc1 100644 --- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java +++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java @@ -18,28 +18,27 @@ */ package domainapp.integtests.tests.modules.simple; -import java.sql.SQLIntegrityConstraintViolationException; -import java.util.List; - -import javax.inject.Inject; +import static org.assertj.core.api.Assertions.assertThat; import com.google.common.base.Throwables; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.Test; - -import org.apache.isis.applib.fixturescripts.FixtureScript; -import org.apache.isis.applib.fixturescripts.FixtureScripts; - import domainapp.dom.modules.simple.SimpleObject; import domainapp.dom.modules.simple.SimpleObjects; import domainapp.fixture.modules.simple.SimpleObjectsTearDown; import domainapp.fixture.scenarios.RecreateSimpleObjects; import domainapp.integtests.tests.SimpleAppIntegTest; -import static org.assertj.core.api.Assertions.assertThat; +import java.sql.SQLIntegrityConstraintViolationException; +import java.util.List; +import javax.inject.Inject; +import org.apache.isis.applib.fixturescripts.FixtureScript; +import org.apache.isis.applib.fixturescripts.FixtureScripts; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.Test; +/** + * Fixture Pattern Integration Test + */ public class SimpleObjectsIntegTest extends SimpleAppIntegTest { @Inject @@ -47,6 +46,9 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest { @Inject SimpleObjects simpleObjects; + /** + * Test Listing of All Simple Objects + */ public static class ListAll extends SimpleObjectsIntegTest { @Test @@ -83,6 +85,10 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest { } } + + /** + * Test Creation of Simple Objects + */ public static class Create extends SimpleObjectsIntegTest { @Test @@ -140,4 +146,4 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest { } } -} \ No newline at end of file +} diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/King.java b/object-mother/src/main/java/com/iluwatar/objectmother/King.java index 544b0bacb..b1b5f3610 100644 --- a/object-mother/src/main/java/com/iluwatar/objectmother/King.java +++ b/object-mother/src/main/java/com/iluwatar/objectmother/King.java @@ -22,6 +22,9 @@ */ package com.iluwatar.objectmother; +/** + * Defines all attributes and behaviour related to the King + */ public class King implements Royalty { boolean isDrunk = false; boolean isHappy = false; @@ -45,11 +48,11 @@ public class King implements Royalty { public void makeUnhappy() { isHappy = false; } - + public boolean isHappy() { return isHappy; } - + /** * Method to flirt to a queen. * @param queen Queen which should be flirted. @@ -61,6 +64,6 @@ public class King implements Royalty { } else { this.makeHappy(); } - + } } diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java b/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java index 3e18fbf3a..e7e488602 100644 --- a/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java +++ b/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java @@ -22,6 +22,9 @@ */ package com.iluwatar.objectmother; +/** + * Defines all attributes and behaviour related to the Queen + */ public class Queen implements Royalty { private boolean isDrunk = false; private boolean isHappy = false; @@ -46,7 +49,7 @@ public class Queen implements Royalty { public void makeUnhappy() { isHappy = false; } - + public boolean isFlirty() { return isFlirty; } @@ -54,7 +57,7 @@ public class Queen implements Royalty { public void setFlirtiness(boolean flirtiness) { this.isFlirty = flirtiness; } - + /** * Method which is called when the king is flirting to a queen. * @param king King who initialized the flirt. diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java b/object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java index 2bebc0939..42271a21d 100644 --- a/object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java +++ b/object-mother/src/main/java/com/iluwatar/objectmother/Royalty.java @@ -22,12 +22,15 @@ */ package com.iluwatar.objectmother; +/** + * Interface contracting Royalty Behaviour + */ public interface Royalty { void makeDrunk(); - + void makeSober(); - + void makeHappy(); - + void makeUnhappy(); } diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java index 624a29132..118253d56 100644 --- a/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java +++ b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java @@ -22,8 +22,11 @@ */ package com.iluwatar.objectmother; +/** + * Object Mother Pattern generating Royalty Types + */ public final class RoyaltyObjectMother { - + /** * Method to create a sober and unhappy king. The standard paramters are set. * @return An instance of {@link com.iluwatar.objectmother.King} with the standard properties. @@ -31,7 +34,7 @@ public final class RoyaltyObjectMother { public static King createSoberUnhappyKing() { return new King(); } - + /** * Method of the object mother to create a drunk king. * @return A drunk {@link com.iluwatar.objectmother.King}. @@ -41,7 +44,7 @@ public final class RoyaltyObjectMother { king.makeDrunk(); return king; } - + /** * Method to create a happy king. * @return A happy {@link com.iluwatar.objectmother.King}. @@ -51,7 +54,7 @@ public final class RoyaltyObjectMother { king.makeHappy(); return king; } - + /** * Method to create a happy and drunk king. * @return A drunk and happy {@link com.iluwatar.objectmother.King}. @@ -62,7 +65,7 @@ public final class RoyaltyObjectMother { king.makeDrunk(); return king; } - + /** * Method to create a flirty queen. * @return A flirty {@link com.iluwatar.objectmother.Queen}. @@ -72,7 +75,7 @@ public final class RoyaltyObjectMother { queen.setFlirtiness(true); return queen; } - + /** * Method to create a not flirty queen. * @return A not flirty {@link com.iluwatar.objectmother.Queen}. diff --git a/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java index ebe536d24..cc5af45aa 100644 --- a/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java +++ b/object-mother/src/test/java/com/iluwatar/objectmother/test/RoyaltyObjectMotherTest.java @@ -33,8 +33,11 @@ import com.iluwatar.objectmother.Queen; import com.iluwatar.objectmother.Royalty; import com.iluwatar.objectmother.RoyaltyObjectMother; +/** + * Test Generation of Royalty Types using the object-mother + */ public class RoyaltyObjectMotherTest { - + @Test public void unsuccessfulKingFlirt() { King soberUnhappyKing = RoyaltyObjectMother.createSoberUnhappyKing(); @@ -42,7 +45,7 @@ public class RoyaltyObjectMotherTest { soberUnhappyKing.flirt(flirtyQueen); assertFalse(soberUnhappyKing.isHappy()); } - + @Test public void queenIsBlockingFlirtCauseDrunkKing() { King drunkUnhappyKing = RoyaltyObjectMother.createDrunkKing(); @@ -50,7 +53,7 @@ public class RoyaltyObjectMotherTest { drunkUnhappyKing.flirt(notFlirtyQueen); assertFalse(drunkUnhappyKing.isHappy()); } - + @Test public void queenIsBlockingFlirt() { King soberHappyKing = RoyaltyObjectMother.createHappyKing(); @@ -58,7 +61,7 @@ public class RoyaltyObjectMotherTest { soberHappyKing.flirt(notFlirtyQueen); assertFalse(soberHappyKing.isHappy()); } - + @Test public void successfullKingFlirt() { King soberHappyKing = RoyaltyObjectMother.createHappyKing(); @@ -66,7 +69,7 @@ public class RoyaltyObjectMotherTest { soberHappyKing.flirt(flirtyQueen); assertTrue(soberHappyKing.isHappy()); } - + @Test public void testQueenType() { Royalty flirtyQueen = RoyaltyObjectMother.createFlirtyQueen(); @@ -74,7 +77,7 @@ public class RoyaltyObjectMotherTest { assertEquals(flirtyQueen.getClass(), Queen.class); assertEquals(notFlirtyQueen.getClass(), Queen.class); } - + @Test public void testKingType() { Royalty drunkKing = RoyaltyObjectMother.createDrunkKing(); diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java index 510d9dc88..f502b86e2 100644 --- a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java +++ b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java @@ -26,8 +26,8 @@ import java.util.HashSet; import java.util.Set; /** - * * Generic object pool + * @param Type T of Object in the Pool */ public abstract class ObjectPool { diff --git a/observer/src/main/java/com/iluwatar/observer/generic/Observer.java b/observer/src/main/java/com/iluwatar/observer/generic/Observer.java index b427aae2c..f8c30853b 100644 --- a/observer/src/main/java/com/iluwatar/observer/generic/Observer.java +++ b/observer/src/main/java/com/iluwatar/observer/generic/Observer.java @@ -23,8 +23,10 @@ package com.iluwatar.observer.generic; /** - * * Observer + * @param Observable + * @param Observer + * @param Action */ public interface Observer, O extends Observer, A> { diff --git a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java index 7120a31e0..70a7922c5 100644 --- a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java +++ b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java @@ -22,18 +22,18 @@ */ package com.iluwatar.observer; +import static org.junit.Assert.assertEquals; + import com.iluwatar.observer.utils.InMemoryAppender; +import java.util.function.Supplier; import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.util.function.Supplier; - -import static org.junit.Assert.assertEquals; - /** * Date: 12/27/15 - 11:44 AM - * + * Weather Observer Tests + * @param Type of WeatherObserver * @author Jeroen Meulemeester */ public abstract class WeatherObserverTest { diff --git a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java index eef89da62..930f7533f 100644 --- a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java +++ b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java @@ -22,19 +22,19 @@ */ package com.iluwatar.observer.generic; +import static org.junit.Assert.assertEquals; + import com.iluwatar.observer.WeatherType; import com.iluwatar.observer.utils.InMemoryAppender; +import java.util.function.Supplier; import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.util.function.Supplier; - -import static org.junit.Assert.assertEquals; - /** * Date: 12/27/15 - 11:44 AM - * + * Test for Observers + * @param Type of Observer * @author Jeroen Meulemeester */ public abstract class ObserverTest { diff --git a/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java b/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java index b0503a4a1..07d5726d0 100644 --- a/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java +++ b/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java @@ -30,6 +30,9 @@ import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.List; +/** + * InMemory Log Appender Util. + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java b/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java index f41a79760..79101f3d3 100644 --- a/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java +++ b/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java @@ -23,15 +23,17 @@ package com.iluwatar.pageobject; +import static org.junit.Assert.assertTrue; + import com.gargoylesoftware.htmlunit.WebClient; import com.iluwatar.pageobject.pages.AlbumListPage; import com.iluwatar.pageobject.pages.AlbumPage; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertTrue; - - +/** + * Test Album Selection and Album Listing + */ public class AlbumListPageTest { private AlbumListPage albumListPage = new AlbumListPage(new WebClient()); diff --git a/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java b/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java index 248a0ddf8..cb07a8293 100644 --- a/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java +++ b/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java @@ -22,14 +22,17 @@ */ package com.iluwatar.pageobject; +import static org.junit.Assert.assertTrue; + import com.gargoylesoftware.htmlunit.WebClient; import com.iluwatar.pageobject.pages.AlbumListPage; import com.iluwatar.pageobject.pages.AlbumPage; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertTrue; - +/** + * Test Album Page Operations + */ public class AlbumPageTest { private AlbumPage albumPage = new AlbumPage(new WebClient()); diff --git a/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java b/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java index a0483ae40..ad10a1927 100644 --- a/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java +++ b/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java @@ -22,14 +22,17 @@ */ package com.iluwatar.pageobject; +import static org.junit.Assert.assertTrue; + import com.gargoylesoftware.htmlunit.WebClient; import com.iluwatar.pageobject.pages.AlbumListPage; import com.iluwatar.pageobject.pages.LoginPage; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertTrue; - +/** + * Test Login Page Object + */ public class LoginPageTest { private LoginPage loginPage = new LoginPage(new WebClient()); diff --git a/poison-pill/src/main/java/com/iluwatar/poison/pill/Message.java b/poison-pill/src/main/java/com/iluwatar/poison/pill/Message.java index cb89f5f5f..cd2d2da6a 100644 --- a/poison-pill/src/main/java/com/iluwatar/poison/pill/Message.java +++ b/poison-pill/src/main/java/com/iluwatar/poison/pill/Message.java @@ -63,6 +63,9 @@ public interface Message { }; + /** + * Enumeration of Type of Headers + */ public enum Headers { DATE, SENDER } diff --git a/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java b/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java index 37a5458b5..bea71ab15 100644 --- a/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java +++ b/private-class-data/src/test/java/com/iluwatar/privateclassdata/utils/InMemoryAppender.java @@ -30,6 +30,9 @@ import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.List; +/** + * InMemory Log Appender Util. + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/promise/src/main/java/com/iluwatar/promise/Utility.java b/promise/src/main/java/com/iluwatar/promise/Utility.java index 525cda338..41e07be45 100644 --- a/promise/src/main/java/com/iluwatar/promise/Utility.java +++ b/promise/src/main/java/com/iluwatar/promise/Utility.java @@ -39,6 +39,9 @@ import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +/** + * Utility to perform various operations + */ public class Utility { private static final Logger LOGGER = LoggerFactory.getLogger(Utility.class); diff --git a/property/src/main/java/com/iluwatar/property/Character.java b/property/src/main/java/com/iluwatar/property/Character.java index db5de2b64..37552fdc8 100644 --- a/property/src/main/java/com/iluwatar/property/Character.java +++ b/property/src/main/java/com/iluwatar/property/Character.java @@ -30,6 +30,9 @@ import java.util.Map; */ public class Character implements Prototype { + /** + * Enumeration of Character types + */ public enum Type { WARRIOR, MAGE, ROGUE } diff --git a/prototype/src/test/java/com/iluwatar/prototype/PrototypeTest.java b/prototype/src/test/java/com/iluwatar/prototype/PrototypeTest.java index c17d08772..add5617b1 100644 --- a/prototype/src/test/java/com/iluwatar/prototype/PrototypeTest.java +++ b/prototype/src/test/java/com/iluwatar/prototype/PrototypeTest.java @@ -22,21 +22,20 @@ */ package com.iluwatar.prototype; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.Arrays; -import java.util.Collection; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; +import java.util.Arrays; +import java.util.Collection; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + /** * Date: 12/28/15 - 8:45 PM - * + * @param

    Prototype * @author Jeroen Meulemeester */ @RunWith(Parameterized.class) diff --git a/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java b/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java index b0c48167d..d78fdc93f 100644 --- a/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java +++ b/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java @@ -30,6 +30,10 @@ import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.List; + +/** + * InMemory Log Appender Util. + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); 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 index c22040418..30624a650 100644 --- 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 @@ -30,6 +30,9 @@ import org.slf4j.LoggerFactory; import java.util.LinkedList; import java.util.List; +/** + * InMemory Log Appender Util. + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java index 0bab0950a..3da46e2ee 100644 --- a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java +++ b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java @@ -34,6 +34,9 @@ import org.springframework.data.jpa.domain.Specification; */ public class PersonSpecifications { + /** + * Specifications stating the Between (From - To) Age Specification + */ public static class AgeBetweenSpec implements Specification { private int from; diff --git a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java index 38649cd96..6786416fa 100644 --- a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java +++ b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java @@ -22,19 +22,18 @@ */ package com.iluwatar.resource.acquisition.is.initialization; +import static org.junit.Assert.assertTrue; + 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.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.LoggerFactory; -import java.util.LinkedList; -import java.util.List; - -import static org.junit.Assert.assertTrue; - /** * Date: 12/28/15 - 9:31 PM * @@ -64,6 +63,9 @@ public class ClosableTest { assertTrue(appender.logContains("Sliding door closes.")); } + /** + * Logging Appender Implementation + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java b/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java index fc01b8329..88255997f 100644 --- a/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java +++ b/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java @@ -23,36 +23,39 @@ package com.iluwatar.semaphore; /** - * Fruit is a resource stored in a FruitBowl. + * Fruit is a resource stored in a FruitBowl. */ public class Fruit { + /** + * Enumeration of Fruit Types + */ public static enum FruitType { ORANGE, APPLE, LEMON } - + private FruitType type; - + public Fruit(FruitType type) { this.type = type; } - + public FruitType getType() { return type; } - + /** * toString method - */ + */ public String toString() { switch (type) { case ORANGE: return "Orange"; - case APPLE: + case APPLE: return "Apple"; - case LEMON: + case LEMON: return "Lemon"; - default: + default: return ""; } } diff --git a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java b/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java index 25dba2a6d..26d274262 100644 --- a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java +++ b/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java @@ -25,10 +25,13 @@ package com.iluwatar.semaphore; import org.junit.Test; import java.io.IOException; +/** + * Application Test Entrypoint + */ public class AppTest{ @Test public void test() throws IOException { String[] args = {}; App.main(args); } -} \ No newline at end of file +} diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/common/BaseDaoTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/common/BaseDaoTest.java index 79c7a0f86..694fc746d 100644 --- a/service-layer/src/test/java/com/iluwatar/servicelayer/common/BaseDaoTest.java +++ b/service-layer/src/test/java/com/iluwatar/servicelayer/common/BaseDaoTest.java @@ -22,23 +22,23 @@ */ package com.iluwatar.servicelayer.common; -import com.iluwatar.servicelayer.hibernate.HibernateUtil; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import com.iluwatar.servicelayer.hibernate.HibernateUtil; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + /** * Date: 12/28/15 - 10:53 PM - * + * Test for Base Data Access Objects + * @param Type of Base Entity + * @param Type of Dao Base Implementation * @author Jeroen Meulemeester */ public abstract class BaseDaoTest> { @@ -142,4 +142,4 @@ public abstract class BaseDaoTest assertEquals(expectedName, entity.toString()); } -} \ No newline at end of file +} diff --git a/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java index e8040ee99..f468ad0b8 100644 --- a/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java +++ b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java @@ -22,7 +22,8 @@ */ package com.iluwatar.singleton; -import org.junit.Test; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import java.util.ArrayList; import java.util.List; @@ -31,9 +32,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.function.Supplier; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; +import org.junit.Test; /** * This class provides several test case that test singleton construction. @@ -43,7 +42,7 @@ import static org.junit.Assert.assertSame; * the same when called in the DIFFERENT thread. * * Date: 12/29/15 - 19:25 PM - * + * @param Supplier method generating singletons * @author Jeroen Meulemeester * @author Richard Jones */ diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java index 70cb23bfe..98ac62613 100644 --- a/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java +++ b/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java @@ -22,23 +22,22 @@ */ package com.iluwatar.templatemethod; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + 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.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.LoggerFactory; -import java.util.LinkedList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - /** * Date: 12/30/15 - 18:12 PM - * + * @param Type of StealingMethod * @author Jeroen Meulemeester */ public abstract class StealingMethodTest { diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java index 8f061575e..b3f253056 100644 --- a/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java +++ b/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java @@ -22,7 +22,8 @@ */ package com.iluwatar.threadpool; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.util.ArrayList; import java.util.List; @@ -34,13 +35,12 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.function.Function; import java.util.stream.Collectors; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import org.junit.Test; /** * Date: 12/30/15 - 18:22 PM - * + * Test for Tasks using a Thread Pool + * @param Type of Task * @author Jeroen Meulemeester */ public abstract class TaskTest { @@ -140,4 +140,4 @@ public abstract class TaskTest { } } -} \ No newline at end of file +} diff --git a/twin/src/test/java/com/iluwatar/twin/BallItemTest.java b/twin/src/test/java/com/iluwatar/twin/BallItemTest.java index 8dfe9515c..5dad02481 100644 --- a/twin/src/test/java/com/iluwatar/twin/BallItemTest.java +++ b/twin/src/test/java/com/iluwatar/twin/BallItemTest.java @@ -22,22 +22,23 @@ */ package com.iluwatar.twin; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoMoreInteractions; + 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.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.slf4j.LoggerFactory; -import java.util.LinkedList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.*; - /** * Date: 12/30/15 - 18:44 PM * @@ -103,6 +104,9 @@ public class BallItemTest { assertEquals(1, appender.getLogSize()); } + /** + * Logging Appender Implementation + */ public class InMemoryAppender extends AppenderBase { private List log = new LinkedList<>(); diff --git a/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java b/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java index 98f0f66dc..ab8470512 100644 --- a/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java +++ b/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java @@ -22,19 +22,19 @@ */ package com.iluwatar.visitor; -import org.junit.Test; - -import java.util.Arrays; -import java.util.function.Function; - import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import java.util.Arrays; +import java.util.function.Function; +import org.junit.Test; + /** * Date: 12/30/15 - 18:59 PM - * + * Test related to Units + * @param Type of Unit * @author Jeroen Meulemeester */ public abstract class UnitTest { @@ -79,4 +79,4 @@ public abstract class UnitTest { */ abstract void verifyVisit(final U unit, final UnitVisitor mockedVisitor); -} \ No newline at end of file +} diff --git a/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java index dbcae196f..ba6705b23 100644 --- a/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java +++ b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java @@ -22,23 +22,23 @@ */ package com.iluwatar.visitor; +import static org.junit.Assert.assertEquals; + 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 java.util.Optional; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.LoggerFactory; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; - -import static org.junit.Assert.assertEquals; - /** * Date: 12/30/15 - 18:59 PM - * + * Test case for Visitor Pattern + * @param Type of UnitVisitor * @author Jeroen Meulemeester */ public abstract class VisitorTest { From c2a7b902a9847d360aa605b7fff7e8cc25847a87 Mon Sep 17 00:00:00 2001 From: NooBxGockeL Date: Sat, 25 Mar 2017 22:07:10 +0100 Subject: [PATCH 208/492] Work on #190: urm/puml updates * added pumlid where it was missing and possible * removed pumlid where it generated a bad image * regenerated some incorrect puml's * added 'left to right direction' puml prefix to some diagrams to improve the automatic layouting --- event-asynchronous/README.md | 11 ++++--- guarded-suspension/README.md | 1 + .../etc/guarded-suspension.urm.puml | 4 +++ hexagonal/README.md | 1 + .../etc/intercepting-filter.urm.puml | 15 ++++----- interpreter/etc/interpreter.urm.puml | 11 ++++--- layers/README.md | 1 + message-channel/README.md | 5 ++- naked-objects/README.md | 1 - object-mother/README.md | 4 +-- observer/etc/observer.urm.puml | 15 ++++----- page-object/README.md | 6 ++-- promise/README.md | 1 + promise/etc/promise.urm.puml | 5 +-- publish-subscribe/README.md | 3 +- queue-load-leveling/README.md | 4 +-- reactor/README.md | 3 +- reactor/etc/reactor.urm.puml | 13 ++++---- service-layer/etc/service-layer.urm.puml | 31 ++++++++++--------- 19 files changed, 73 insertions(+), 62 deletions(-) diff --git a/event-asynchronous/README.md b/event-asynchronous/README.md index ef35d0b38..4c26e0a3c 100644 --- a/event-asynchronous/README.md +++ b/event-asynchronous/README.md @@ -12,11 +12,12 @@ tags: ## Intent The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many -of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:- -(1) Perform time-consuming tasks, such as downloads and database operations, "in the background," without interrupting your application. -(2) Execute multiple operations simultaneously, receiving notifications when each completes. -(3) Wait for resources to become available without stopping ("hanging") your application. -(4) Communicate with pending asynchronous operations using the familiar events-and-delegates model. +of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to: + +1. Perform time-consuming tasks, such as downloads and database operations, "in the background," without interrupting your application. +2. Execute multiple operations simultaneously, receiving notifications when each completes. +3. Wait for resources to become available without stopping ("hanging") your application. +4. Communicate with pending asynchronous operations using the familiar events-and-delegates model. ![alt text](./etc/event-asynchronous.png "Event-based Asynchronous") diff --git a/guarded-suspension/README.md b/guarded-suspension/README.md index 35044f9b2..3e00539a2 100644 --- a/guarded-suspension/README.md +++ b/guarded-suspension/README.md @@ -3,6 +3,7 @@ layout: pattern title: Guarded Suspension folder: guarded-suspension permalink: /patterns/guarded-suspension/ +pumlid: ROux3W8n30LxJW47IDnJxLLCOcMD4YVoXxq-eQTwev56UeSvgiVejmTBwL4fjDzFzsLF0CKhD_OpNc6aPOgJU2vp0FUuSAVmnW-cIiPDqa9tKZ4OQ1kW1MgbcYniaHXF0VBoH-VGaTVlnK5Iztu1 categories: Concurrency tags: - Java diff --git a/guarded-suspension/etc/guarded-suspension.urm.puml b/guarded-suspension/etc/guarded-suspension.urm.puml index f99607d82..45a7d3790 100644 --- a/guarded-suspension/etc/guarded-suspension.urm.puml +++ b/guarded-suspension/etc/guarded-suspension.urm.puml @@ -1,5 +1,9 @@ @startuml package com.iluwatar.guarded.suspension { + class App { + + App() + + main(args : String[]) {static} + } class GuardedQueue { - LOGGER : Logger {static} - sourceList : Queue diff --git a/hexagonal/README.md b/hexagonal/README.md index 88908421d..dc1566625 100644 --- a/hexagonal/README.md +++ b/hexagonal/README.md @@ -4,6 +4,7 @@ title: Hexagonal Architecture folder: hexagonal permalink: /patterns/hexagonal/ pumlid: HSTB4W8X30N0g-W1XkozpPD90LO8L3wEnzUTk-xxq2fvSfhSUiJs1v7XAcr4psSwMrqQh57gcZGaBmICNdZZEDb7qsCZWasT9lm7wln1MmeXZlfVIPjbvvGl +pumlformat: svg categories: Architectural tags: - Java diff --git a/intercepting-filter/etc/intercepting-filter.urm.puml b/intercepting-filter/etc/intercepting-filter.urm.puml index 5c1e79ee4..74444c2d0 100644 --- a/intercepting-filter/etc/intercepting-filter.urm.puml +++ b/intercepting-filter/etc/intercepting-filter.urm.puml @@ -1,4 +1,5 @@ @startuml +left to right direction package com.iluwatar.intercepting.filter { abstract class AbstractFilter { - next : Filter @@ -79,10 +80,10 @@ AbstractFilter --> "-next" Filter DListener --+ Target FilterChain --> "-chain" Filter FilterManager --> "-filterChain" FilterChain -AbstractFilter ..|> Filter -AddressFilter --|> AbstractFilter -ContactFilter --|> AbstractFilter -DepositFilter --|> AbstractFilter -NameFilter --|> AbstractFilter -OrderFilter --|> AbstractFilter -@enduml \ No newline at end of file +AbstractFilter ..|> Filter +AddressFilter --|> AbstractFilter +ContactFilter --|> AbstractFilter +DepositFilter --|> AbstractFilter +NameFilter --|> AbstractFilter +OrderFilter --|> AbstractFilter +@enduml diff --git a/interpreter/etc/interpreter.urm.puml b/interpreter/etc/interpreter.urm.puml index e79ad1989..e1286a2a9 100644 --- a/interpreter/etc/interpreter.urm.puml +++ b/interpreter/etc/interpreter.urm.puml @@ -1,4 +1,5 @@ @startuml +left to right direction package com.iluwatar.interpreter { class App { - LOGGER : Logger {static} @@ -44,8 +45,8 @@ package com.iluwatar.interpreter { MultiplyExpression --> "-leftExpression" Expression MinusExpression --> "-leftExpression" Expression PlusExpression --> "-leftExpression" Expression -MinusExpression --|> Expression -MultiplyExpression --|> Expression -NumberExpression --|> Expression -PlusExpression --|> Expression -@enduml \ No newline at end of file +MinusExpression --|> Expression +MultiplyExpression --|> Expression +NumberExpression --|> Expression +PlusExpression --|> Expression +@enduml diff --git a/layers/README.md b/layers/README.md index d62c6b6b7..8eac62412 100644 --- a/layers/README.md +++ b/layers/README.md @@ -4,6 +4,7 @@ title: Layers folder: layers permalink: /patterns/layers/ pumlid: BSR13OCm30NGLSe0n7UsCS62L8w9x6yGszD3t-bDpQhc9kdwEO0H2v7pNVQ68zSCyNeQn53gsQbftWns-lB5yoRHTfi70-8Mr3b-8UL7F4XG_otflOpi-W80 +pumlformat: svg categories: Architectural tags: - Java diff --git a/message-channel/README.md b/message-channel/README.md index aa357ac0c..09361dd4a 100644 --- a/message-channel/README.md +++ b/message-channel/README.md @@ -3,9 +3,8 @@ layout: pattern title: Message Channel folder: message-channel permalink: /patterns/message-channel/ -pumlid: NSZB3SCm203GLTe1RExTXX1akm9YyMdMRy-zFRtdCf8wkLmUCtF72y3nxcFbhAE2dIvBjknqAIof6nCTtlZ1TdAiOMrZ9hi5ACOFe1o1WnjDD6C1Jlg_NgvzbyeN categories: Integration -tags: +tags: - Java - EIP - Apache Camel™ @@ -24,4 +23,4 @@ Use the Message Channel pattern when ## Real world examples -* [akka-camel](http://doc.akka.io/docs/akka/snapshot/scala/camel.html) \ No newline at end of file +* [akka-camel](http://doc.akka.io/docs/akka/snapshot/scala/camel.html) diff --git a/naked-objects/README.md b/naked-objects/README.md index 14391dd40..66e6ac2b0 100644 --- a/naked-objects/README.md +++ b/naked-objects/README.md @@ -3,7 +3,6 @@ layout: pattern title: Naked Objects folder: naked-objects permalink: /patterns/naked-objects/ -pumlid: LSX15i8W30N0g-W187jlaq9igH1uoO_r-BfrDs_kJKkFAc7zTW3B7qJ6LzuRZjZ2nSfKY2ANEQZrk1XiTFARKnLlkwR5W9Ww3VOVIFabDStjb08dGVcVz6mVX4aE6td5w5y0 categories: Architectural tags: - Java diff --git a/object-mother/README.md b/object-mother/README.md index 9188c8b41..cda3336cf 100644 --- a/object-mother/README.md +++ b/object-mother/README.md @@ -3,7 +3,7 @@ layout: pattern title: Object Mother folder: object-mother permalink: /patterns/object-mother/ -pumlid: +pumlid: LOr13iCW30JlVKNx0E3UKxxYW9KGWK7sklb-wR6dtLbfj9k15DxRurKbDo_isfudCEsTaj8TZuhJTpVMF0GiY7dqL9lVjDHqqOT2OQk7X4a0grZgPAkaiL-S4Vh0kOYH_vVeskFyVMyiPUKN categories: Creational tags: - Java @@ -28,4 +28,4 @@ Use the Object Mother pattern when * [c2wiki - Object Mother](http://c2.com/cgi/wiki?ObjectMother) -* [Nat Pryce - Test Data Builders: an alternative to the Object Mother pattern](http://www.natpryce.com/articles/000714.html) \ No newline at end of file +* [Nat Pryce - Test Data Builders: an alternative to the Object Mother pattern](http://www.natpryce.com/articles/000714.html) diff --git a/observer/etc/observer.urm.puml b/observer/etc/observer.urm.puml index bea9aab53..5d046d880 100644 --- a/observer/etc/observer.urm.puml +++ b/observer/etc/observer.urm.puml @@ -1,4 +1,5 @@ @startuml +left to right direction package com.iluwatar.observer { class App { - LOGGER : Logger {static} @@ -71,10 +72,10 @@ package com.iluwatar.observer.generic { Weather --> "-currentWeather" WeatherType GWeather --> "-currentWeather" WeatherType Weather --> "-observers" WeatherObserver -Hobbits ..|> WeatherObserver -Orcs ..|> WeatherObserver -GHobbits ..|> Race -GOrcs ..|> Race -GWeather --|> Observable -Race --|> Observer -@enduml \ No newline at end of file +Hobbits ..|> WeatherObserver +Orcs ..|> WeatherObserver +GHobbits ..|> Race +GOrcs ..|> Race +GWeather --|> Observable +Race --|> Observer +@enduml diff --git a/page-object/README.md b/page-object/README.md index 2219a077c..16c021dfb 100644 --- a/page-object/README.md +++ b/page-object/README.md @@ -3,7 +3,6 @@ layout: pattern title: Page Object folder: page-object permalink: /patterns/page-object/ -pumlid: JSV14OGW30NGLjO28FVj9iOCua1Wme-sxnxtzjvMJLeS6ju-9p3NbyZvoQNYZ3sMkWo36hACJhN5ms2dYszEXwvQB4q6r6rHv_K3JIwQndwfW1Jo_npUyupUNW00 categories: Testing tags: - Java @@ -12,7 +11,7 @@ tags: ## Intent -Page Object encapsulates the UI, hiding the underlying UI widgetry of an application (commonly a web application) and providing an application-specific API to allow the manipulation of UI components required for tests. In doing so, it allows the test class itself to focus on the test logic instead. +Page Object encapsulates the UI, hiding the underlying UI widgetry of an application (commonly a web application) and providing an application-specific API to allow the manipulation of UI components required for tests. In doing so, it allows the test class itself to focus on the test logic instead. ![alt text](./etc/page-object.png "Page Object") @@ -22,11 +21,10 @@ Page Object encapsulates the UI, hiding the underlying UI widgetry of an applica Use the Page Object pattern when -* You are writing automated tests for your web application and you want to separate the UI manipulation required for the tests from the actual test logic. +* You are writing automated tests for your web application and you want to separate the UI manipulation required for the tests from the actual test logic. * Make your tests less brittle, and more readable and robust ## Credits * [Martin Fowler - PageObject](http://martinfowler.com/bliki/PageObject.html) * [Selenium - Page Objects](https://github.com/SeleniumHQ/selenium/wiki/PageObjects) - diff --git a/promise/README.md b/promise/README.md index 638bb3ef5..65d463550 100644 --- a/promise/README.md +++ b/promise/README.md @@ -3,6 +3,7 @@ layout: pattern title: Promise folder: promise permalink: /patterns/promise/ +pumlid: DOqv4i8m301xNW4FYDLJvIl2rYHYBDcZWtmVKr3jDZkxUw15IhyzM6lFHcdzVaPCVm8ONkNWEFELJbQ71ccKEWIuvuKhXJT-S6laVEWsCO9C7GHz2KmRmav0KVzUqgJCtsydROjV categories: Concurrency tags: - Java diff --git a/promise/etc/promise.urm.puml b/promise/etc/promise.urm.puml index 45cae7ff1..8aabc1d2a 100644 --- a/promise/etc/promise.urm.puml +++ b/promise/etc/promise.urm.puml @@ -1,4 +1,5 @@ @startuml +left to right direction package com.iluwatar.promise { class App { - DEFAULT_URL : String {static} @@ -70,9 +71,9 @@ package com.iluwatar.promise { + lowestFrequencyChar(charFrequency : Map) : Character {static} } } -TransformAction --> "-src" Promise TransformAction --+ Promise +TransformAction --> "-src" Promise ConsumeAction --+ Promise ConsumeAction --> "-src" Promise Promise --|> PromiseSupport -@enduml \ No newline at end of file +@enduml diff --git a/publish-subscribe/README.md b/publish-subscribe/README.md index 3265e42ea..462209074 100644 --- a/publish-subscribe/README.md +++ b/publish-subscribe/README.md @@ -3,9 +3,8 @@ layout: pattern title: Publish Subscribe folder: publish-subscribe permalink: /patterns/publish-subscribe/ -pumlid: PSZB3SCm203GLTe1RExT1XCKKs5YyMdMR--zFRsd66aTNAwFcRdZ1U1uzrDorgXWfykIBJjT2qJhnaI7Dtwm7HnoMjkOoMu12-C7s3LKOhQe4UGo63ZfVtlvwhkMVW40 categories: Integration -tags: +tags: - Java - EIP - Apache Camel™ diff --git a/queue-load-leveling/README.md b/queue-load-leveling/README.md index 126d19176..ca73ac34a 100644 --- a/queue-load-leveling/README.md +++ b/queue-load-leveling/README.md @@ -3,7 +3,7 @@ layout: pattern title: Queue based load leveling folder: queue-load-leveling permalink: /patterns/queue-load-leveling/ -pumlid: +pumlid: ROux3W8n30LxJW47IDnJxLLCOcM376VnP_VwX9xgZKOQwMtcg1w3RuykXQDIADztzyEU08fNRjttU8MHbYbEuhdC0PtZmfN26qzCbQmtIGUwauh1G5i0dw2Wn1DhOZg9kpGWB_zy3Xtv-FtOIEhQBm00 categories: Other tags: - Java @@ -34,4 +34,4 @@ for both the task and the service. ## Credits -* [Microsoft Cloud Design Patterns: Queue-Based Load Leveling Pattern](https://msdn.microsoft.com/en-us/library/dn589783.aspx) \ No newline at end of file +* [Microsoft Cloud Design Patterns: Queue-Based Load Leveling Pattern](https://msdn.microsoft.com/en-us/library/dn589783.aspx) diff --git a/reactor/README.md b/reactor/README.md index 7fd3982ad..68461cfdd 100644 --- a/reactor/README.md +++ b/reactor/README.md @@ -4,8 +4,9 @@ title: Reactor folder: reactor permalink: /patterns/reactor/ pumlid: DSR14OGm20NGLjO23FVj1f7Hx2Ga0nzjVxtuJc-f9YrtJM-V4vZn9NA-or5nvfQXBiEWXYAZKsrvCzZfnnUlkqOzR9qCg5jGvtX2hYmOJWfvNz9xcTdR7m00 +pumlformat: svg categories: Concurrency -tags: +tags: - Java - Difficulty-Expert - I/O diff --git a/reactor/etc/reactor.urm.puml b/reactor/etc/reactor.urm.puml index cc56eae7a..1ce92cab2 100644 --- a/reactor/etc/reactor.urm.puml +++ b/reactor/etc/reactor.urm.puml @@ -1,4 +1,5 @@ @startuml +left to right direction package com.iluwatar.reactor.framework { abstract class AbstractNioChannel { - channel : SelectableChannel @@ -147,9 +148,9 @@ App --> "-channels" AbstractNioChannel DatagramPacket ..+ NioDatagramChannel App --> "-dispatcher" Dispatcher ChangeKeyOpsCommand --+ NioReactor -LoggingHandler ..|> ChannelHandler -NioDatagramChannel --|> AbstractNioChannel -NioServerSocketChannel --|> AbstractNioChannel -SameThreadDispatcher ..|> Dispatcher -ThreadPoolDispatcher ..|> Dispatcher -@enduml \ No newline at end of file +LoggingHandler ..|> ChannelHandler +NioDatagramChannel --|> AbstractNioChannel +NioServerSocketChannel --|> AbstractNioChannel +SameThreadDispatcher ..|> Dispatcher +ThreadPoolDispatcher ..|> Dispatcher +@enduml diff --git a/service-layer/etc/service-layer.urm.puml b/service-layer/etc/service-layer.urm.puml index ff870a5e9..6cf9b938d 100644 --- a/service-layer/etc/service-layer.urm.puml +++ b/service-layer/etc/service-layer.urm.puml @@ -1,4 +1,5 @@ @startuml +left to right direction package com.iluwatar.servicelayer.hibernate { class HibernateUtil { - LOGGER : Logger {static} @@ -143,18 +144,18 @@ MagicServiceImpl --> "-spellbookDao" SpellbookDao MagicServiceImpl --> "-spellDao" SpellDao Spellbook --> "-spells" Spell Spellbook --> "-wizards" Wizard -DaoBaseImpl ..|> Dao -MagicServiceImpl ..|> MagicService -Spell --|> BaseEntity -SpellDao --|> Dao -SpellDaoImpl ..|> SpellDao -SpellDaoImpl --|> DaoBaseImpl -Spellbook --|> BaseEntity -SpellbookDao --|> Dao -SpellbookDaoImpl ..|> SpellbookDao -SpellbookDaoImpl --|> DaoBaseImpl -Wizard --|> BaseEntity -WizardDao --|> Dao -WizardDaoImpl ..|> WizardDao -WizardDaoImpl --|> DaoBaseImpl -@enduml \ No newline at end of file +DaoBaseImpl ..|> Dao +MagicServiceImpl ..|> MagicService +Spell --|> BaseEntity +SpellDao --|> Dao +SpellDaoImpl ..|> SpellDao +SpellDaoImpl --|> DaoBaseImpl +Spellbook --|> BaseEntity +SpellbookDao --|> Dao +SpellbookDaoImpl ..|> SpellbookDao +SpellbookDaoImpl --|> DaoBaseImpl +Wizard --|> BaseEntity +WizardDao --|> Dao +WizardDaoImpl ..|> WizardDao +WizardDaoImpl --|> DaoBaseImpl +@enduml From 6ba4d7be98bbff255d0fdd280ae357ec10a5798e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 1 Apr 2017 12:39:06 +0300 Subject: [PATCH 209/492] #77 Add missing license header --- .../main/java/com/iluwatar/tls/Result.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tls/src/main/java/com/iluwatar/tls/Result.java b/tls/src/main/java/com/iluwatar/tls/Result.java index 951a02a2f..69ec5c502 100644 --- a/tls/src/main/java/com/iluwatar/tls/Result.java +++ b/tls/src/main/java/com/iluwatar/tls/Result.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ /* * Fiducia IT AG, All rights reserved. Use is subject to license terms. */ From 2921448f8bc39cdb9a917eb0a312eb45a75dd234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 1 Apr 2017 14:25:13 +0300 Subject: [PATCH 210/492] #497 Add missing puml and license headers --- converter/etc/converter.urm.puml | 49 +++++++++++++++++++ converter/pom.xml | 24 +++++++++ .../com/iluwatar/converter/ConverterTest.java | 22 +++++++++ 3 files changed, 95 insertions(+) create mode 100644 converter/etc/converter.urm.puml diff --git a/converter/etc/converter.urm.puml b/converter/etc/converter.urm.puml new file mode 100644 index 000000000..5e0acf191 --- /dev/null +++ b/converter/etc/converter.urm.puml @@ -0,0 +1,49 @@ +@startuml +package com.iluwatar.converter { + class App { + + App() + + main(args : String[]) {static} + } + class Converter { + - fromDto : Function + - fromEntity : Function + + Converter(fromDto : Function, fromEntity : Function) + + convertFromDto(userDto : T) : U + + convertFromEntity(user : U) : T + + createFromDtos(dtoUsers : Collection) : List + + createFromEntities(users : Collection) : List + } + class User { + - firstName : String + - isActive : boolean + - lastName : String + - userId : String + + User(firstName : String, lastName : String, isActive : boolean, userId : String) + + equals(o : Object) : boolean + + getFirstName() : String + + getLastName() : String + + getUserId() : String + + hashCode() : int + + isActive() : boolean + + toString() : String + } + class UserConverter { + + UserConverter() + } + class UserDto { + - email : String + - firstName : String + - isActive : boolean + - lastName : String + + UserDto(firstName : String, lastName : String, isActive : boolean, email : String) + + equals(o : Object) : boolean + + getEmail() : String + + getFirstName() : String + + getLastName() : String + + hashCode() : int + + isActive() : boolean + + toString() : String + } +} +UserConverter --|> Converter +@enduml \ No newline at end of file diff --git a/converter/pom.xml b/converter/pom.xml index 026f30d40..01f1171a1 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -1,4 +1,28 @@ + diff --git a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java index eccb81cf9..5bf820605 100644 --- a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java +++ b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.converter; import com.google.common.collect.Lists; From c1c4411957c0f93f482d8bb00e99892d1e28a713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 1 Apr 2017 15:34:13 +0300 Subject: [PATCH 211/492] #539 Checkstyle fixes --- balking/src/main/java/com/iluwatar/balking/WashingMachine.java | 3 +++ converter/src/main/java/com/iluwatar/converter/User.java | 3 +++ converter/src/main/java/com/iluwatar/converter/UserDto.java | 3 +++ 3 files changed, 9 insertions(+) diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java index 2167a0e52..e4f1259ad 100644 --- a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java +++ b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java @@ -25,6 +25,9 @@ package com.iluwatar.balking; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Washing machine class + */ public class WashingMachine { private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class); diff --git a/converter/src/main/java/com/iluwatar/converter/User.java b/converter/src/main/java/com/iluwatar/converter/User.java index f40c01e79..62903a931 100644 --- a/converter/src/main/java/com/iluwatar/converter/User.java +++ b/converter/src/main/java/com/iluwatar/converter/User.java @@ -25,6 +25,9 @@ package com.iluwatar.converter; import java.util.Objects; +/** + * User class + */ public class User { private String firstName; private String lastName; diff --git a/converter/src/main/java/com/iluwatar/converter/UserDto.java b/converter/src/main/java/com/iluwatar/converter/UserDto.java index 8f55bbe0e..8eacc0b3b 100644 --- a/converter/src/main/java/com/iluwatar/converter/UserDto.java +++ b/converter/src/main/java/com/iluwatar/converter/UserDto.java @@ -26,6 +26,9 @@ package com.iluwatar.converter; import java.util.Objects; +/** + * User DTO class + */ public class UserDto { private String firstName; From f3c4640d1220084c65074c59e7857a1e8ee26745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 1 Apr 2017 15:43:36 +0300 Subject: [PATCH 212/492] #539 More Checkstyle fixes --- converter/src/test/java/com/iluwatar/converter/AppTest.java | 3 +++ .../src/test/java/com/iluwatar/converter/ConverterTest.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/converter/src/test/java/com/iluwatar/converter/AppTest.java b/converter/src/test/java/com/iluwatar/converter/AppTest.java index 5198827d2..091fbe2ca 100644 --- a/converter/src/test/java/com/iluwatar/converter/AppTest.java +++ b/converter/src/test/java/com/iluwatar/converter/AppTest.java @@ -24,6 +24,9 @@ package com.iluwatar.converter; import org.junit.Test; +/** + * App running test + */ public class AppTest { @Test diff --git a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java index 5bf820605..9fc2e2a0c 100644 --- a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java +++ b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java @@ -31,6 +31,9 @@ import java.util.Random; import static junit.framework.TestCase.assertEquals; +/** + * Tests for {@link Converter} + */ public class ConverterTest { private UserConverter userConverter = new UserConverter(); From 139876f96a920dfdcb1b51fb5fbda57fb855065b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 1 Apr 2017 15:51:01 +0300 Subject: [PATCH 213/492] #539 Checkstyle fix --- .../src/test/java/com/iluwatar/balking/WashingMachineTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java index 3dc87d64f..ecf81f409 100644 --- a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java +++ b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java @@ -30,6 +30,9 @@ import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; +/** + * Tests for {@link WashingMachine} + */ public class WashingMachineTest { private volatile WashingMachineState machineStateGlobal; From 8fea969912d42830b9ac09d20dafa83ef4e5c45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 1 Apr 2017 17:14:02 +0300 Subject: [PATCH 214/492] Reached milestone 1.15.0 --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- balking/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- command/pom.xml | 2 +- composite/pom.xml | 2 +- converter/pom.xml | 2 +- dao/pom.xml | 2 +- data-mapper/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-asynchronous/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- execute-around/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- guarded-suspension/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- message-channel/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- module/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-mother/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- publish-subscribe/pom.xml | 2 +- queue-load-leveling/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- singleton/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strategy/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- tls/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- twin/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 100 files changed, 103 insertions(+), 103 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index 85215a021..766deabb3 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index e3129f6f0..f1d37068c 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 abstract-factory diff --git a/adapter/pom.xml b/adapter/pom.xml index 83462f28c..aa87cb8d5 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 64b27f12d..1a7c75845 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index 3cb68099b..2a323e06d 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index 027105e7f..145f1d430 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index a38975177..e7ff8819c 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 aggregator-microservices diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index 3bd2392fa..4e820b0f5 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index d42b31933..73bc99c48 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index de2b3f099..dd07d1828 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index 8a9a6f379..6cb04d753 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index dc5b64404..dda91cfce 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 async-method-invocation diff --git a/balking/pom.xml b/balking/pom.xml index ad066aee6..f33a74fdb 100644 --- a/balking/pom.xml +++ b/balking/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/bridge/pom.xml b/bridge/pom.xml index ec04ff395..f67ec274b 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 bridge diff --git a/builder/pom.xml b/builder/pom.xml index 305de70bd..69177f27b 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index d5fde8ea3..fa8f1658d 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 business-delegate diff --git a/caching/pom.xml b/caching/pom.xml index 6d866eb03..632f9d70a 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 caching diff --git a/callback/pom.xml b/callback/pom.xml index 2b8d1fec6..f07bc276a 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 callback diff --git a/chain/pom.xml b/chain/pom.xml index 81aaf7e1f..1a3d0be20 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 chain diff --git a/command/pom.xml b/command/pom.xml index e50be3e3d..e7810fb03 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 command diff --git a/composite/pom.xml b/composite/pom.xml index 107502963..5b5e2a0bc 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 composite diff --git a/converter/pom.xml b/converter/pom.xml index 01f1171a1..350bf4d7f 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/dao/pom.xml b/dao/pom.xml index 374a1c14c..5f23fbd12 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 dao diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index c23868a4e..1d5a05e60 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 data-mapper diff --git a/decorator/pom.xml b/decorator/pom.xml index 51684065c..ae3eb99ec 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index cf0349024..a6f18882d 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index 603bb2c05..eb83e5321 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index 0b0541b8f..f73ff254b 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index b15e76f88..ce2520aef 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index 3bf8c281b..ed5113f59 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 event-aggregator diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index 9fecfa606..5aa2eef38 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 event-asynchronous diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index 2ced1abda..1ddc66232 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 event-driven-architecture diff --git a/execute-around/pom.xml b/execute-around/pom.xml index acc36b4b4..f07fe309e 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 execute-around diff --git a/facade/pom.xml b/facade/pom.xml index 0f1fa8688..97dc8c338 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index f356fc3b8..06cf9b7e3 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index d6359ff03..a7625ff64 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index e2635f228..46e558c2d 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index 8d815079c..b26c29fb4 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index aa0c95796..667e851f5 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index 2c210a0ca..162402ab0 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index 11802d2f5..88d7bcebc 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 front-controller diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index b51de54e1..12b7efbc7 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 jar guarded-suspension diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index 4b3285ff1..7a199b09c 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index 2cf88b626..0557aa545 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index 2c23edff2..d02047137 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index a932e10b4..743326b48 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 3fcdd9852..74ad6fed4 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 iterator diff --git a/layers/pom.xml b/layers/pom.xml index 13604cb0e..3d012389d 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index 2ed0a1020..d4d4ba144 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 lazy-loading diff --git a/mediator/pom.xml b/mediator/pom.xml index b9fda50a5..7b20330af 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 mediator diff --git a/memento/pom.xml b/memento/pom.xml index e6cd095d9..eeef15c41 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 memento diff --git a/message-channel/pom.xml b/message-channel/pom.xml index 98b2a0c2e..6198e6ffa 100644 --- a/message-channel/pom.xml +++ b/message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 message-channel diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index 29823d9e8..82fabee55 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 6c43a0048..9d3ccdf6b 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 model-view-presenter model-view-presenter diff --git a/module/pom.xml b/module/pom.xml index 8920916cb..f1338d3e6 100644 --- a/module/pom.xml +++ b/module/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 module diff --git a/monad/pom.xml b/monad/pom.xml index 63d6431db..adb0b3b4f 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 monad diff --git a/monostate/pom.xml b/monostate/pom.xml index bc025fdeb..498e79b06 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index 34cc4ae8d..aabc72576 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index d68b016f9..036bb759b 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index d42a2fdab..a12ba29da 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 39560b5c0..895a8a8d2 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0-SNAPSHOT + 1.15.0 naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index a96c24626..b11796435 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0-SNAPSHOT + 1.15.0 naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index 32ec4cd6b..d44c045f4 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0-SNAPSHOT + 1.15.0 naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index d8acdc745..c71209513 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -15,7 +15,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 naked-objects @@ -367,17 +367,17 @@ ${project.groupId} naked-objects-dom - 1.15.0-SNAPSHOT + 1.15.0 ${project.groupId} naked-objects-fixture - 1.15.0-SNAPSHOT + 1.15.0 ${project.groupId} naked-objects-webapp - 1.15.0-SNAPSHOT + 1.15.0 diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 7e6d3ffcd..45d413128 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0-SNAPSHOT + 1.15.0 naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index 2c494e3b7..4fa75ceeb 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 null-object diff --git a/object-mother/pom.xml b/object-mother/pom.xml index fc7d96a85..4c8a8252c 100644 --- a/object-mother/pom.xml +++ b/object-mother/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 object-mother diff --git a/object-pool/pom.xml b/object-pool/pom.xml index 19ac48956..4ab51470a 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 object-pool diff --git a/observer/pom.xml b/observer/pom.xml index bb313552c..f52be8ab1 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 observer diff --git a/page-object/pom.xml b/page-object/pom.xml index 35ee916a5..aec481498 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 page-object diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index e518649cf..ecb9ccfdc 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 poison-pill diff --git a/pom.xml b/pom.xml index 4b22adeb6..a548b6bf1 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 pom 2014 diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index 957e18033..496b48283 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index dbc80614f..8570d98bc 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index a93ef2ba5..5bf362613 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 promise diff --git a/property/pom.xml b/property/pom.xml index 4b28b9f54..bf0840739 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 property diff --git a/prototype/pom.xml b/prototype/pom.xml index 995757d5a..4145ac538 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index f12db724c..bf32d8556 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 proxy diff --git a/publish-subscribe/pom.xml b/publish-subscribe/pom.xml index 1586815c1..ee6a6720b 100644 --- a/publish-subscribe/pom.xml +++ b/publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 publish-subscribe diff --git a/queue-load-leveling/pom.xml b/queue-load-leveling/pom.xml index 351f94906..6167570cb 100644 --- a/queue-load-leveling/pom.xml +++ b/queue-load-leveling/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 queue-load-leveling diff --git a/reactor/pom.xml b/reactor/pom.xml index 1d3aa22e7..69dccf542 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index a46f6f5b2..d811d3c8b 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 5cae0466f..879d1b58e 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index ecf304ad2..92707a5bb 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 resource-acquisition-is-initialization diff --git a/semaphore/pom.xml b/semaphore/pom.xml index 34b6bf629..22ee544c6 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 semaphore diff --git a/servant/pom.xml b/servant/pom.xml index fc59c795b..f861ae746 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 servant diff --git a/service-layer/pom.xml b/service-layer/pom.xml index 3d9e5e26f..af0d96a02 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index 397955f8e..4046670a0 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 service-locator diff --git a/singleton/pom.xml b/singleton/pom.xml index 8ddcb2131..c68d58235 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 singleton diff --git a/specification/pom.xml b/specification/pom.xml index 40584b7ca..8a58a8dd6 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 specification diff --git a/state/pom.xml b/state/pom.xml index 18a2608cd..f0245dfd9 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index b33f48fb7..5d63f0187 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.15.0-SNAPSHOT + 1.15.0 step-builder diff --git a/strategy/pom.xml b/strategy/pom.xml index c47281228..88749d2cb 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 strategy diff --git a/template-method/pom.xml b/template-method/pom.xml index 4a40c89fb..81ac4ddfb 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index a3b8d1fe6..127fdad8d 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 thread-pool diff --git a/tls/pom.xml b/tls/pom.xml index fa8bf6860..3ab25fadd 100644 --- a/tls/pom.xml +++ b/tls/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 tls diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index da580631d..ee983bbba 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 tolerant-reader diff --git a/twin/pom.xml b/twin/pom.xml index b9f6fb6ee..2b57a6cd4 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 twin diff --git a/value-object/pom.xml b/value-object/pom.xml index ae18ed94a..4b9958fa5 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index 2aeeb73b0..48a68386c 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.15.0 visitor From 073d06c0ae9cf4277bd54a7195c28420c6b8efb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 1 Apr 2017 17:15:59 +0300 Subject: [PATCH 215/492] Set version for next development iteration --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- balking/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- command/pom.xml | 2 +- composite/pom.xml | 2 +- converter/pom.xml | 2 +- dao/pom.xml | 2 +- data-mapper/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-asynchronous/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- execute-around/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- guarded-suspension/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- message-channel/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- module/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-mother/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- publish-subscribe/pom.xml | 2 +- queue-load-leveling/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- singleton/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strategy/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- tls/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- twin/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 100 files changed, 103 insertions(+), 103 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index 766deabb3..54b157df6 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index f1d37068c..d37159409 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT abstract-factory diff --git a/adapter/pom.xml b/adapter/pom.xml index aa87cb8d5..8cf754618 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 1a7c75845..477ce00c8 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index 2a323e06d..234daa25d 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index 145f1d430..bdd96eec9 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index e7ff8819c..e08ee58f8 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 aggregator-microservices diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index 4e820b0f5..e36b09fd4 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index 73bc99c48..b9430ff69 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index dd07d1828..7fdc54f8a 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index 6cb04d753..68dc75640 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index dda91cfce..1dc9a6b73 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT async-method-invocation diff --git a/balking/pom.xml b/balking/pom.xml index f33a74fdb..2e27d9332 100644 --- a/balking/pom.xml +++ b/balking/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/bridge/pom.xml b/bridge/pom.xml index f67ec274b..7c60f8ef8 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT bridge diff --git a/builder/pom.xml b/builder/pom.xml index 69177f27b..806d61b0a 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index fa8f1658d..6ac3d9f4f 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT business-delegate diff --git a/caching/pom.xml b/caching/pom.xml index 632f9d70a..6ec90234d 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT caching diff --git a/callback/pom.xml b/callback/pom.xml index f07bc276a..a64ddac51 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT callback diff --git a/chain/pom.xml b/chain/pom.xml index 1a3d0be20..7b283b012 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT chain diff --git a/command/pom.xml b/command/pom.xml index e7810fb03..cbf851701 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT command diff --git a/composite/pom.xml b/composite/pom.xml index 5b5e2a0bc..f3b1a38b5 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT composite diff --git a/converter/pom.xml b/converter/pom.xml index 350bf4d7f..569899f1d 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/dao/pom.xml b/dao/pom.xml index 5f23fbd12..b7de27bd4 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT dao diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index 1d5a05e60..878f02fed 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT data-mapper diff --git a/decorator/pom.xml b/decorator/pom.xml index ae3eb99ec..5b6d24723 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index a6f18882d..befd02a59 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index eb83e5321..ccbbea9a2 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index f73ff254b..7e19561de 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index ce2520aef..c87efc185 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index ed5113f59..276aecd0c 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT event-aggregator diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index 5aa2eef38..a10fec55d 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT event-asynchronous diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index 1ddc66232..f021f4023 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT event-driven-architecture diff --git a/execute-around/pom.xml b/execute-around/pom.xml index f07fe309e..765b52846 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT execute-around diff --git a/facade/pom.xml b/facade/pom.xml index 97dc8c338..a9a1ed226 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT facade diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml index 06cf9b7e3..0fef94e84 100644 --- a/factory-kit/pom.xml +++ b/factory-kit/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT factory-kit diff --git a/factory-method/pom.xml b/factory-method/pom.xml index a7625ff64..8cc506c62 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT factory-method diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml index 46e558c2d..7fbb085f2 100644 --- a/feature-toggle/pom.xml +++ b/feature-toggle/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml index b26c29fb4..cc243123b 100644 --- a/fluentinterface/pom.xml +++ b/fluentinterface/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT 4.0.0 diff --git a/flux/pom.xml b/flux/pom.xml index 667e851f5..158ca8c65 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT flux diff --git a/flyweight/pom.xml b/flyweight/pom.xml index 162402ab0..d9574b589 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT flyweight diff --git a/front-controller/pom.xml b/front-controller/pom.xml index 88d7bcebc..082fe27c0 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT front-controller diff --git a/guarded-suspension/pom.xml b/guarded-suspension/pom.xml index 12b7efbc7..b7423d1eb 100644 --- a/guarded-suspension/pom.xml +++ b/guarded-suspension/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT jar guarded-suspension diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index 7a199b09c..2952f8d54 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT half-sync-half-async diff --git a/hexagonal/pom.xml b/hexagonal/pom.xml index 0557aa545..9af418fbb 100644 --- a/hexagonal/pom.xml +++ b/hexagonal/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT hexagonal diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index d02047137..e5082ef00 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT intercepting-filter diff --git a/interpreter/pom.xml b/interpreter/pom.xml index 743326b48..a9c4126d4 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT interpreter diff --git a/iterator/pom.xml b/iterator/pom.xml index 74ad6fed4..c05c78d3c 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT iterator diff --git a/layers/pom.xml b/layers/pom.xml index 3d012389d..621facbea 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index d4d4ba144..4e95046bf 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT lazy-loading diff --git a/mediator/pom.xml b/mediator/pom.xml index 7b20330af..b48324472 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT mediator diff --git a/memento/pom.xml b/memento/pom.xml index eeef15c41..0990844f7 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT memento diff --git a/message-channel/pom.xml b/message-channel/pom.xml index 6198e6ffa..91c631313 100644 --- a/message-channel/pom.xml +++ b/message-channel/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT message-channel diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index 82fabee55..bf7ace403 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT model-view-controller diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 9d3ccdf6b..2eeedc6df 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT model-view-presenter model-view-presenter diff --git a/module/pom.xml b/module/pom.xml index f1338d3e6..caa66cb54 100644 --- a/module/pom.xml +++ b/module/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT module diff --git a/monad/pom.xml b/monad/pom.xml index adb0b3b4f..694ba71ed 100644 --- a/monad/pom.xml +++ b/monad/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT monad diff --git a/monostate/pom.xml b/monostate/pom.xml index 498e79b06..be7ba99a4 100644 --- a/monostate/pom.xml +++ b/monostate/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT monostate diff --git a/multiton/pom.xml b/multiton/pom.xml index aabc72576..b4dd361ae 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT multiton diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index 036bb759b..0fedbf901 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT mute-idiom diff --git a/mutex/pom.xml b/mutex/pom.xml index a12ba29da..0a3ad9e93 100644 --- a/mutex/pom.xml +++ b/mutex/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT mutex diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index 895a8a8d2..9b98700b8 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0 + 1.16.0-SNAPSHOT naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index b11796435..e48ec5b30 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0 + 1.16.0-SNAPSHOT naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index d44c045f4..7389e5cef 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0 + 1.16.0-SNAPSHOT naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index c71209513..d2cf69296 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -15,7 +15,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT naked-objects @@ -367,17 +367,17 @@ ${project.groupId} naked-objects-dom - 1.15.0 + 1.16.0-SNAPSHOT ${project.groupId} naked-objects-fixture - 1.15.0 + 1.16.0-SNAPSHOT ${project.groupId} naked-objects-webapp - 1.15.0 + 1.16.0-SNAPSHOT diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 45d413128..c415050bc 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.15.0 + 1.16.0-SNAPSHOT naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index 4fa75ceeb..6f96d777c 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT null-object diff --git a/object-mother/pom.xml b/object-mother/pom.xml index 4c8a8252c..f2f933e49 100644 --- a/object-mother/pom.xml +++ b/object-mother/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT object-mother diff --git a/object-pool/pom.xml b/object-pool/pom.xml index 4ab51470a..bf2e3d4ae 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT object-pool diff --git a/observer/pom.xml b/observer/pom.xml index f52be8ab1..a854aaada 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT observer diff --git a/page-object/pom.xml b/page-object/pom.xml index aec481498..748342d99 100644 --- a/page-object/pom.xml +++ b/page-object/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT page-object diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index ecb9ccfdc..c1c8432a1 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT poison-pill diff --git a/pom.xml b/pom.xml index a548b6bf1..4b9740857 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT pom 2014 diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index 496b48283..de75796dc 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT private-class-data diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml index 8570d98bc..ccdfc135a 100644 --- a/producer-consumer/pom.xml +++ b/producer-consumer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT producer-consumer diff --git a/promise/pom.xml b/promise/pom.xml index 5bf362613..1b20fd784 100644 --- a/promise/pom.xml +++ b/promise/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT promise diff --git a/property/pom.xml b/property/pom.xml index bf0840739..b488f8e57 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT property diff --git a/prototype/pom.xml b/prototype/pom.xml index 4145ac538..a73223b9c 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT prototype diff --git a/proxy/pom.xml b/proxy/pom.xml index bf32d8556..293f3098d 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT proxy diff --git a/publish-subscribe/pom.xml b/publish-subscribe/pom.xml index ee6a6720b..3f969eac9 100644 --- a/publish-subscribe/pom.xml +++ b/publish-subscribe/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT publish-subscribe diff --git a/queue-load-leveling/pom.xml b/queue-load-leveling/pom.xml index 6167570cb..3966dd4db 100644 --- a/queue-load-leveling/pom.xml +++ b/queue-load-leveling/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT queue-load-leveling diff --git a/reactor/pom.xml b/reactor/pom.xml index 69dccf542..ca6440318 100644 --- a/reactor/pom.xml +++ b/reactor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT reactor diff --git a/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml index d811d3c8b..7a873c551 100644 --- a/reader-writer-lock/pom.xml +++ b/reader-writer-lock/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT reader-writer-lock diff --git a/repository/pom.xml b/repository/pom.xml index 879d1b58e..cbb431e39 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index 92707a5bb..fae94e91c 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT resource-acquisition-is-initialization diff --git a/semaphore/pom.xml b/semaphore/pom.xml index 22ee544c6..1d606ae6c 100644 --- a/semaphore/pom.xml +++ b/semaphore/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT semaphore diff --git a/servant/pom.xml b/servant/pom.xml index f861ae746..185076b59 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT servant diff --git a/service-layer/pom.xml b/service-layer/pom.xml index af0d96a02..8028bcaea 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT service-layer diff --git a/service-locator/pom.xml b/service-locator/pom.xml index 4046670a0..3c9551770 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT service-locator diff --git a/singleton/pom.xml b/singleton/pom.xml index c68d58235..672807527 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT singleton diff --git a/specification/pom.xml b/specification/pom.xml index 8a58a8dd6..33cc0f1e5 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT specification diff --git a/state/pom.xml b/state/pom.xml index f0245dfd9..7c0e9ab3f 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT state diff --git a/step-builder/pom.xml b/step-builder/pom.xml index 5d63f0187..e98069d60 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.15.0 + 1.16.0-SNAPSHOT step-builder diff --git a/strategy/pom.xml b/strategy/pom.xml index 88749d2cb..d29f4b2ba 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT strategy diff --git a/template-method/pom.xml b/template-method/pom.xml index 81ac4ddfb..a2ceadc10 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index 127fdad8d..2efd4cb50 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT thread-pool diff --git a/tls/pom.xml b/tls/pom.xml index 3ab25fadd..99849bf22 100644 --- a/tls/pom.xml +++ b/tls/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT tls diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index ee983bbba..4e614e44c 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT tolerant-reader diff --git a/twin/pom.xml b/twin/pom.xml index 2b57a6cd4..15b2e3094 100644 --- a/twin/pom.xml +++ b/twin/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT twin diff --git a/value-object/pom.xml b/value-object/pom.xml index 4b9958fa5..90716fbcc 100644 --- a/value-object/pom.xml +++ b/value-object/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT value-object diff --git a/visitor/pom.xml b/visitor/pom.xml index 48a68386c..9acd24003 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.15.0 + 1.16.0-SNAPSHOT visitor From 960eee3d4369779e6898e96a1e15876ce528c44b Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 18:04:16 +0100 Subject: [PATCH 216/492] #467 update version --- data-bus/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-bus/pom.xml b/data-bus/pom.xml index 01f5649ab..0cfe32612 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -33,7 +33,7 @@ com.iluwatar java-design-patterns - 1.15.0-SNAPSHOT + 1.16.0-SNAPSHOT data-bus From bc4d029a8719a98b9667cf3785c1ec28372db1c3 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 18:04:44 +0100 Subject: [PATCH 217/492] #467 data-bus: pom.xml: remove surefire plugin --- data-bus/pom.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/data-bus/pom.xml b/data-bus/pom.xml index 0cfe32612..b2e246c3d 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -49,16 +49,4 @@ provided - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.19 - - false - - - - From 146f36718835ba66e5c9c40d703dc4c0777a6d6c Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 18:12:32 +0100 Subject: [PATCH 218/492] #467 data-bus: remove lombok --- data-bus/pom.xml | 6 ------ .../main/java/com/iluwatar/databus/App.java | 6 ++---- .../com/iluwatar/databus/data/MessageData.java | 6 ++++-- .../iluwatar/databus/data/StartingData.java | 6 ++++-- .../iluwatar/databus/data/StoppingData.java | 6 ++++-- .../databus/members/CounterMember.java | 14 +++++++++----- .../iluwatar/databus/members/StatusMember.java | 18 +++++++++++------- 7 files changed, 34 insertions(+), 28 deletions(-) diff --git a/data-bus/pom.xml b/data-bus/pom.xml index b2e246c3d..9e9f6a70a 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -42,11 +42,5 @@ junit test - - org.projectlombok - lombok - ${lombok.version} - provided - diff --git a/data-bus/src/main/java/com/iluwatar/databus/App.java b/data-bus/src/main/java/com/iluwatar/databus/App.java index b76873cec..2dff853b9 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/App.java +++ b/data-bus/src/main/java/com/iluwatar/databus/App.java @@ -23,12 +23,11 @@ package com.iluwatar.databus; -import com.iluwatar.databus.data.StoppingData; -import com.iluwatar.databus.data.StartingData; import com.iluwatar.databus.data.MessageData; +import com.iluwatar.databus.data.StartingData; +import com.iluwatar.databus.data.StoppingData; import com.iluwatar.databus.members.CounterMember; import com.iluwatar.databus.members.StatusMember; -import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; @@ -39,7 +38,6 @@ import java.time.LocalDateTime; * * @author Paul Campbell (pcampbell@kemitix.net) */ -@Slf4j class App { public static void main(String[] args) { diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java b/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java index 2750b013e..934022be9 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java +++ b/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java @@ -25,18 +25,20 @@ package com.iluwatar.databus.data; import com.iluwatar.databus.AbstractDataType; import com.iluwatar.databus.DataType; -import lombok.RequiredArgsConstructor; /** * . * * @author Paul Campbell (pcampbell@kemitix.net) */ -@RequiredArgsConstructor public class MessageData extends AbstractDataType { private final String message; + public MessageData(String message) { + this.message = message; + } + public String getMessage() { return message; } diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java b/data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java index f7159b77a..ac7391f1a 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java +++ b/data-bus/src/main/java/com/iluwatar/databus/data/StartingData.java @@ -25,7 +25,6 @@ package com.iluwatar.databus.data; import com.iluwatar.databus.AbstractDataType; import com.iluwatar.databus.DataType; -import lombok.RequiredArgsConstructor; import java.time.LocalDateTime; @@ -34,11 +33,14 @@ import java.time.LocalDateTime; * * @author Paul Campbell (pcampbell@kemitix.net) */ -@RequiredArgsConstructor public class StartingData extends AbstractDataType { private final LocalDateTime when; + public StartingData(LocalDateTime when) { + this.when = when; + } + public LocalDateTime getWhen() { return when; } diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java b/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java index 57918ec4c..b5e30568f 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java +++ b/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java @@ -25,7 +25,6 @@ package com.iluwatar.databus.data; import com.iluwatar.databus.AbstractDataType; import com.iluwatar.databus.DataType; -import lombok.RequiredArgsConstructor; import java.time.LocalDateTime; @@ -34,11 +33,14 @@ import java.time.LocalDateTime; * * @author Paul Campbell (pcampbell@kemitix.net) */ -@RequiredArgsConstructor public class StoppingData extends AbstractDataType { private final LocalDateTime when; + public StoppingData(LocalDateTime when) { + this.when = when; + } + public LocalDateTime getWhen() { return when; } diff --git a/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java b/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java index 45c90abb0..d43bf4bab 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java +++ b/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java @@ -26,20 +26,24 @@ package com.iluwatar.databus.members; import com.iluwatar.databus.DataType; import com.iluwatar.databus.Member; import com.iluwatar.databus.data.MessageData; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + +import java.util.logging.Logger; /** * Receiver of Data-Bus events. * * @author Paul Campbell (pcampbell@kemitix.net) */ -@Slf4j -@RequiredArgsConstructor public class CounterMember implements Member { + private static final Logger LOGGER = Logger.getLogger(CounterMember.class.getName()); + private final String name; + public CounterMember(String name) { + this.name = name; + } + @Override public void accept(final DataType data) { if (data instanceof MessageData) { @@ -48,6 +52,6 @@ public class CounterMember implements Member { } private void handleEvent(MessageData data) { - log.info("{} sees message {}", name, data.getMessage()); + LOGGER.info(String.format("%s sees message %s", name, data.getMessage())); } } diff --git a/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java b/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java index 5e1ca1656..f11e1e0ab 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java +++ b/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java @@ -28,20 +28,24 @@ import com.iluwatar.databus.Member; import com.iluwatar.databus.data.MessageData; import com.iluwatar.databus.data.StartingData; import com.iluwatar.databus.data.StoppingData; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; + +import java.util.logging.Logger; /** * Receiver of Data-Bus events. * * @author Paul Campbell (pcampbell@kemitix.net) */ -@Slf4j -@RequiredArgsConstructor public class StatusMember implements Member { + private static final Logger LOGGER = Logger.getLogger(StatusMember.class.getName()); + private final int id; + public StatusMember(int id) { + this.id = id; + } + @Override public void accept(final DataType data) { if (data instanceof StartingData) { @@ -52,12 +56,12 @@ public class StatusMember implements Member { } private void handleEvent(StartingData data) { - log.info("Receiver #{} sees application started at {}", id, data.getWhen()); + LOGGER.info(String.format("Receiver #%d sees application started at %s", id, data.getWhen())); } private void handleEvent(StoppingData data) { - log.info("Receiver #{} sees application stopping at {}", id, data.getWhen()); - log.info("Receiver #{} sending goodbye message", id); + LOGGER.info(String.format("Receiver #%d sees application stopping at %s", id, data.getWhen())); + LOGGER.info(String.format("Receiver #%d sending goodbye message", id)); data.getDataBus().publish(MessageData.of(String.format("Goodbye cruel world from #%d!", id))); } } From 86009f2261ce9cfd952121c4b00a1ebad4888de4 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 18:12:56 +0100 Subject: [PATCH 219/492] #467 data-bus: add missing javadoc --- .../src/main/java/com/iluwatar/databus/AbstractDataType.java | 2 +- .../src/main/java/com/iluwatar/databus/data/MessageData.java | 2 +- .../src/main/java/com/iluwatar/databus/data/StoppingData.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java b/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java index 8926ce9aa..5ba6653de 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java +++ b/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java @@ -25,7 +25,7 @@ SOFTWARE. package com.iluwatar.databus; /** - * . + * Base for data to send via the Data-Bus. * * @author Paul Campbell (pcampbell@kemitix.net) */ diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java b/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java index 934022be9..ac541cf20 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java +++ b/data-bus/src/main/java/com/iluwatar/databus/data/MessageData.java @@ -27,7 +27,7 @@ import com.iluwatar.databus.AbstractDataType; import com.iluwatar.databus.DataType; /** - * . + * An event raised when a string message is sent. * * @author Paul Campbell (pcampbell@kemitix.net) */ diff --git a/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java b/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java index b5e30568f..976fdc4e9 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java +++ b/data-bus/src/main/java/com/iluwatar/databus/data/StoppingData.java @@ -29,7 +29,7 @@ import com.iluwatar.databus.DataType; import java.time.LocalDateTime; /** - * . + * An event raised when applications stops, containing the stop time of the application. * * @author Paul Campbell (pcampbell@kemitix.net) */ From 46e0fa4825446bc95afda26d68799a0acadf4ef4 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 18:35:40 +0100 Subject: [PATCH 220/492] #467 data-bus: pom.xml: add mockito dependency --- data-bus/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/data-bus/pom.xml b/data-bus/pom.xml index 9e9f6a70a..68065f00a 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -42,5 +42,10 @@ junit test + + org.mockito + mockito-core + test + From b7a6a018e06bda3e546f174b39278c1846c69d33 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 18:36:04 +0100 Subject: [PATCH 221/492] #467 data-bus: DataBusTest: added --- .../com/iluwatar/databus/DataBusTest.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java diff --git a/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java b/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java new file mode 100644 index 000000000..90c326ebf --- /dev/null +++ b/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java @@ -0,0 +1,52 @@ +package com.iluwatar.databus; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.never; + +/** + * Tests for {@link DataBus}. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +public class DataBusTest { + + @Mock + private Member member; + + @Mock + private DataType event; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void publishedEventIsReceivedBySubscribedMember() { + //given + final DataBus dataBus = DataBus.getInstance(); + dataBus.subscribe(member); + //when + dataBus.publish(event); + //then + then(member).should().accept(event); + } + + @Test + public void publishedEventIsNotReceivedByMemberAfterUnsubscribing() { + //given + final DataBus dataBus = DataBus.getInstance(); + dataBus.subscribe(member); + dataBus.unsubscribe(member); + //when + dataBus.publish(event); + //then + then(member).should(never()).accept(event); + } + +} From 8b0c14cae0096ba0fd7f6ac22394711c720bcfba Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 19:04:28 +0100 Subject: [PATCH 222/492] Counter doesn't count anything. Added ability to collect the messages from the MessageData that it receives. --- .../main/java/com/iluwatar/databus/App.java | 6 +++--- ...Member.java => MessageCollectorMember.java} | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) rename data-bus/src/main/java/com/iluwatar/databus/members/{CounterMember.java => MessageCollectorMember.java} (75%) diff --git a/data-bus/src/main/java/com/iluwatar/databus/App.java b/data-bus/src/main/java/com/iluwatar/databus/App.java index 2dff853b9..aa67ff420 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/App.java +++ b/data-bus/src/main/java/com/iluwatar/databus/App.java @@ -26,7 +26,7 @@ package com.iluwatar.databus; import com.iluwatar.databus.data.MessageData; import com.iluwatar.databus.data.StartingData; import com.iluwatar.databus.data.StoppingData; -import com.iluwatar.databus.members.CounterMember; +import com.iluwatar.databus.members.MessageCollectorMember; import com.iluwatar.databus.members.StatusMember; import java.time.LocalDateTime; @@ -44,8 +44,8 @@ class App { final DataBus bus = DataBus.getInstance(); bus.subscribe(new StatusMember(1)); bus.subscribe(new StatusMember(2)); - final CounterMember foo = new CounterMember("Foo"); - final CounterMember bar = new CounterMember("Bar"); + final MessageCollectorMember foo = new MessageCollectorMember("Foo"); + final MessageCollectorMember bar = new MessageCollectorMember("Bar"); bus.subscribe(foo); bus.publish(StartingData.of(LocalDateTime.now())); bus.publish(MessageData.of("Only Foo should see this")); diff --git a/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java b/data-bus/src/main/java/com/iluwatar/databus/members/MessageCollectorMember.java similarity index 75% rename from data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java rename to data-bus/src/main/java/com/iluwatar/databus/members/MessageCollectorMember.java index d43bf4bab..a8ee94ad5 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/members/CounterMember.java +++ b/data-bus/src/main/java/com/iluwatar/databus/members/MessageCollectorMember.java @@ -27,20 +27,25 @@ import com.iluwatar.databus.DataType; import com.iluwatar.databus.Member; import com.iluwatar.databus.data.MessageData; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.logging.Logger; /** - * Receiver of Data-Bus events. + * Receiver of Data-Bus events that collects the messages from each {@link MessageData}. * * @author Paul Campbell (pcampbell@kemitix.net) */ -public class CounterMember implements Member { +public class MessageCollectorMember implements Member { - private static final Logger LOGGER = Logger.getLogger(CounterMember.class.getName()); + private static final Logger LOGGER = Logger.getLogger(MessageCollectorMember.class.getName()); private final String name; - public CounterMember(String name) { + private List messages = new ArrayList<>(); + + public MessageCollectorMember(String name) { this.name = name; } @@ -53,5 +58,10 @@ public class CounterMember implements Member { private void handleEvent(MessageData data) { LOGGER.info(String.format("%s sees message %s", name, data.getMessage())); + messages.add(data.getMessage()); + } + + public List getMessages() { + return Collections.unmodifiableList(messages); } } From f495a88e915a1cc894d231b3911ae619f4536a54 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 19:04:48 +0100 Subject: [PATCH 223/492] #467 data-bus: members: MessageCollectorMemberTest: added --- .../members/MessageCollectorMemberTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java diff --git a/data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java b/data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java new file mode 100644 index 000000000..96fc090ee --- /dev/null +++ b/data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java @@ -0,0 +1,40 @@ +package com.iluwatar.databus.members; + +import com.iluwatar.databus.data.MessageData; +import com.iluwatar.databus.data.StartingData; +import org.junit.Assert; +import org.junit.Test; + +import java.time.LocalDateTime; + +/** + * Tests for {@link MessageCollectorMember}. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +public class MessageCollectorMemberTest { + + @Test + public void collectMessageFromMessageData() { + //given + final String message = "message"; + final MessageData messageData = new MessageData(message); + final MessageCollectorMember collector = new MessageCollectorMember("collector"); + //when + collector.accept(messageData); + //then + Assert.assertTrue(collector.getMessages().contains(message)); + } + + @Test + public void collectIgnoresMessageFromOtherDataTypes() { + //given + final StartingData startingData = new StartingData(LocalDateTime.now()); + final MessageCollectorMember collector = new MessageCollectorMember("collector"); + //when + collector.accept(startingData); + //then + Assert.assertEquals(0, collector.getMessages().size()); + } + +} From 311bb7987017c65e5ac18c06abc09253cc69a17c Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 19:16:55 +0100 Subject: [PATCH 224/492] #467 data-bus: members: StatusMember: records start and stop times --- .../databus/members/StatusMember.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java b/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java index f11e1e0ab..803e2df20 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java +++ b/data-bus/src/main/java/com/iluwatar/databus/members/StatusMember.java @@ -29,6 +29,7 @@ import com.iluwatar.databus.data.MessageData; import com.iluwatar.databus.data.StartingData; import com.iluwatar.databus.data.StoppingData; +import java.time.LocalDateTime; import java.util.logging.Logger; /** @@ -42,6 +43,10 @@ public class StatusMember implements Member { private final int id; + private LocalDateTime started; + + private LocalDateTime stopped; + public StatusMember(int id) { this.id = id; } @@ -56,12 +61,22 @@ public class StatusMember implements Member { } private void handleEvent(StartingData data) { - LOGGER.info(String.format("Receiver #%d sees application started at %s", id, data.getWhen())); + started = data.getWhen(); + LOGGER.info(String.format("Receiver #%d sees application started at %s", id, started)); } private void handleEvent(StoppingData data) { - LOGGER.info(String.format("Receiver #%d sees application stopping at %s", id, data.getWhen())); + stopped = data.getWhen(); + LOGGER.info(String.format("Receiver #%d sees application stopping at %s", id, stopped)); LOGGER.info(String.format("Receiver #%d sending goodbye message", id)); data.getDataBus().publish(MessageData.of(String.format("Goodbye cruel world from #%d!", id))); } + + public LocalDateTime getStarted() { + return started; + } + + public LocalDateTime getStopped() { + return stopped; + } } From b72d5453496929e793310c004973d42449bc1e0e Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 19:17:09 +0100 Subject: [PATCH 225/492] #467 data-bus: members: StatusMemberTest: added --- .../databus/members/StatusMemberTest.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java diff --git a/data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java b/data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java new file mode 100644 index 000000000..e5983dcea --- /dev/null +++ b/data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java @@ -0,0 +1,57 @@ +package com.iluwatar.databus.members; + +import com.iluwatar.databus.DataBus; +import com.iluwatar.databus.data.MessageData; +import com.iluwatar.databus.data.StartingData; +import com.iluwatar.databus.data.StoppingData; +import org.junit.Assert; +import org.junit.Test; + +import java.time.LocalDateTime; +import java.time.Month; + +/** + * Tests for {@link StatusMember}. + * + * @author Paul Campbell (pcampbell@kemitix.net) + */ +public class StatusMemberTest { + + @Test + public void statusRecordsTheStartTime() { + //given + final LocalDateTime startTime = LocalDateTime.of(2017, Month.APRIL, 1, 19, 9); + final StartingData startingData = new StartingData(startTime); + final StatusMember statusMember = new StatusMember(1); + //when + statusMember.accept(startingData); + //then + Assert.assertEquals(startTime, statusMember.getStarted()); + } + + @Test + public void statusRecordsTheStopTime() { + //given + final LocalDateTime stop = LocalDateTime.of(2017, Month.APRIL, 1, 19, 12); + final StoppingData stoppingData = new StoppingData(stop); + stoppingData.setDataBus(DataBus.getInstance()); + final StatusMember statusMember = new StatusMember(1); + //when + statusMember.accept(stoppingData); + //then + Assert.assertEquals(stop, statusMember.getStopped()); + } + + @Test + public void statusIgnoresMessageData() { + //given + final MessageData messageData = new MessageData("message"); + final StatusMember statusMember = new StatusMember(1); + //when + statusMember.accept(messageData); + //then + Assert.assertNull(statusMember.getStarted()); + Assert.assertNull(statusMember.getStopped()); + } + +} From c96ebcb197b192f65d4c96a3ad493b4c318acb4c Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 19:26:41 +0100 Subject: [PATCH 226/492] #467 data-bus: App: add description of the pattern --- data-bus/src/main/java/com/iluwatar/databus/App.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/data-bus/src/main/java/com/iluwatar/databus/App.java b/data-bus/src/main/java/com/iluwatar/databus/App.java index aa67ff420..42746db98 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/App.java +++ b/data-bus/src/main/java/com/iluwatar/databus/App.java @@ -35,6 +35,17 @@ import java.time.LocalDateTime; * The Data Bus pattern *

    *

    {@see http://wiki.c2.com/?DataBusPattern}

    + *

    + *

    The Data-Bus pattern provides a method where different parts of an application may + * pass messages between each other without needing to be aware of the other's existence.

    + *

    Similar to the {@code ObserverPattern}, members register themselves with the {@link DataBus} + * and may then receive each piece of data that is published to the Data-Bus. The member + * may react to any given message or not.

    + *

    It allows for Many-to-Many distribution of data, as there may be any number of + * publishers to a Data-Bus, and any number of members receiving the data. All members + * will receive the same data, the order each receives a given piece of data, is an + * implementation detail.

    + *

    Members may unsubscribe from the Data-Bus to stop receiving data.

    * * @author Paul Campbell (pcampbell@kemitix.net) */ From 2643dfa0b8dc084966911779b1aebd6f272d44bb Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 1 Apr 2017 19:33:54 +0100 Subject: [PATCH 227/492] #467 data-bus: App: add notes about this implementation of the patter --- data-bus/src/main/java/com/iluwatar/databus/App.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data-bus/src/main/java/com/iluwatar/databus/App.java b/data-bus/src/main/java/com/iluwatar/databus/App.java index 42746db98..748bb6af0 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/App.java +++ b/data-bus/src/main/java/com/iluwatar/databus/App.java @@ -46,6 +46,16 @@ import java.time.LocalDateTime; * will receive the same data, the order each receives a given piece of data, is an * implementation detail.

    *

    Members may unsubscribe from the Data-Bus to stop receiving data.

    + *

    This example of the pattern implements a Synchronous Data-Bus, meaning that + * when data is published to the Data-Bus, the publish method will not return until + * all members have received the data and returned.

    + *

    The {@link DataBus} class is a Singleton.

    + *

    Members of the Data-Bus must implement the {@link Member} interface.

    + *

    Data to be published via the Data-Bus must implement the {@link DataType} interface.

    + *

    The {@code data} package contains example {@link DataType} implementations.

    + *

    The {@code members} package contains example {@link Member} implementations.

    + *

    The {@link StatusMember} demonstrates using the DataBus to publish a message + * to the Data-Bus when it receives a message.

    * * @author Paul Campbell (pcampbell@kemitix.net) */ From 60ebcc56f84d2f190b7d1a04af80fddc3a59bced Mon Sep 17 00:00:00 2001 From: Sunil Mogadati Date: Sat, 1 Apr 2017 20:55:47 -0600 Subject: [PATCH 228/492] #507 SonarQube blocker severity bugs --- .../model/view/presenter/FileLoader.java | 4 +-- .../queue/load/leveling/ServiceExecutor.java | 10 +++--- .../servicelayer/common/DaoBaseImpl.java | 19 +++++++---- .../servicelayer/spell/SpellDaoImpl.java | 2 +- .../spellbook/SpellbookDaoImpl.java | 2 +- .../servicelayer/wizard/WizardDaoImpl.java | 2 +- .../tolerantreader/RainbowFishSerializer.java | 34 +++++++++---------- 7 files changed, 38 insertions(+), 35 deletions(-) diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java index c9b023925..01af677ae 100644 --- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java +++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java @@ -48,8 +48,7 @@ public class FileLoader { * Loads the data of the file specified. */ public String loadData() { - try { - BufferedReader br = new BufferedReader(new FileReader(new File(this.fileName))); + try (BufferedReader br = new BufferedReader(new FileReader(new File(this.fileName)))) { StringBuilder sb = new StringBuilder(); String line; @@ -58,7 +57,6 @@ public class FileLoader { } this.loaded = true; - br.close(); return sb.toString(); } catch (Exception e) { diff --git a/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/ServiceExecutor.java b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/ServiceExecutor.java index 63dbec69f..2b423ffaf 100644 --- a/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/ServiceExecutor.java +++ b/queue-load-leveling/src/main/java/com/iluwatar/queue/load/leveling/ServiceExecutor.java @@ -35,27 +35,27 @@ import org.slf4j.LoggerFactory; public class ServiceExecutor implements Runnable { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); - + private final MessageQueue msgQueue; public ServiceExecutor(MessageQueue msgQueue) { this.msgQueue = msgQueue; } - + /** * The ServiceExecutor thread will retrieve each message and process it. */ public void run() { try { - while (true) { + while (!Thread.currentThread().isInterrupted()) { Message msg = msgQueue.retrieveMsg(); - + if (null != msg) { LOGGER.info(msg.toString() + " is served."); } else { LOGGER.info("Service Executor: Waiting for Messages to serve .. "); } - + Thread.sleep(1000); } } catch (InterruptedException ie) { diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java index 70feb1a00..401c4170c 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java @@ -27,6 +27,7 @@ import java.util.List; import org.hibernate.Criteria; import org.hibernate.Session; +import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.criterion.Restrictions; @@ -45,13 +46,17 @@ public abstract class DaoBaseImpl implements Dao { protected Class persistentClass = (Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; - protected Session getSession() { - return HibernateUtil.getSessionFactory().openSession(); + /* + * Making this getSessionFactory() instead of getSession() so that it is the responsibility + * of the caller to open as well as close the session (prevents potential resource leak). + */ + protected SessionFactory getSessionFactory() { + return HibernateUtil.getSessionFactory(); } @Override public E find(Long id) { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; E result = null; try { @@ -73,7 +78,7 @@ public abstract class DaoBaseImpl implements Dao { @Override public void persist(E entity) { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; try { tx = session.beginTransaction(); @@ -91,7 +96,7 @@ public abstract class DaoBaseImpl implements Dao { @Override public E merge(E entity) { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; E result = null; try { @@ -111,7 +116,7 @@ public abstract class DaoBaseImpl implements Dao { @Override public void delete(E entity) { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; try { tx = session.beginTransaction(); @@ -129,7 +134,7 @@ public abstract class DaoBaseImpl implements Dao { @Override public List findAll() { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; List result = null; try { diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java index b280b1250..81b3b6189 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java @@ -38,7 +38,7 @@ public class SpellDaoImpl extends DaoBaseImpl implements SpellDao { @Override public Spell findByName(String name) { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; Spell result = null; try { diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java index 7724583ab..c7131b843 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java @@ -38,7 +38,7 @@ public class SpellbookDaoImpl extends DaoBaseImpl implements Spellboo @Override public Spellbook findByName(String name) { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; Spellbook result = null; try { diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java index 67a37e969..0014bf921 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java @@ -39,7 +39,7 @@ public class WizardDaoImpl extends DaoBaseImpl implements WizardDao { @Override public Wizard findByName(String name) { - Session session = getSession(); + Session session = getSessionFactory().openSession(); Transaction tx = null; Wizard result = null; try { diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java index d0ad5d798..7445dec4d 100644 --- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java +++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java @@ -52,11 +52,10 @@ public final class RainbowFishSerializer { map.put("age", String.format("%d", rainbowFish.getAge())); map.put("lengthMeters", String.format("%d", rainbowFish.getLengthMeters())); map.put("weightTons", String.format("%d", rainbowFish.getWeightTons())); - FileOutputStream fileOut = new FileOutputStream(filename); - ObjectOutputStream objOut = new ObjectOutputStream(fileOut); - objOut.writeObject(map); - objOut.close(); - fileOut.close(); + try (FileOutputStream fileOut = new FileOutputStream(filename); + ObjectOutputStream objOut = new ObjectOutputStream(fileOut)) { + objOut.writeObject(map); + } } /** @@ -71,23 +70,24 @@ public final class RainbowFishSerializer { map.put("angry", Boolean.toString(rainbowFish.getAngry())); map.put("hungry", Boolean.toString(rainbowFish.getHungry())); map.put("sleeping", Boolean.toString(rainbowFish.getSleeping())); - FileOutputStream fileOut = new FileOutputStream(filename); - ObjectOutputStream objOut = new ObjectOutputStream(fileOut); - objOut.writeObject(map); - objOut.close(); - fileOut.close(); + try (FileOutputStream fileOut = new FileOutputStream(filename); + ObjectOutputStream objOut = new ObjectOutputStream(fileOut)) { + objOut.writeObject(map); + } } /** * Read V1 RainbowFish from file */ public static RainbowFish readV1(String filename) throws IOException, ClassNotFoundException { - FileInputStream fileIn = new FileInputStream(filename); - ObjectInputStream objIn = new ObjectInputStream(fileIn); - Map map = (Map) objIn.readObject(); - objIn.close(); - fileIn.close(); - return new RainbowFish(map.get("name"), Integer.parseInt(map.get("age")), Integer.parseInt(map - .get("lengthMeters")), Integer.parseInt(map.get("weightTons"))); + Map map = null; + + try (FileInputStream fileIn = new FileInputStream(filename); + ObjectInputStream objIn = new ObjectInputStream(fileIn)) { + map = (Map) objIn.readObject(); + } + + return new RainbowFish(map.get("name"), Integer.parseInt(map.get("age")), Integer.parseInt(map.get("lengthMeters")), + Integer.parseInt(map.get("weightTons"))); } } From dce767c1c5e46e071d4de42a6bb504afa21d940f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Thu, 6 Apr 2017 23:48:15 +0200 Subject: [PATCH 229/492] first commit --- event-queue/README.md | 0 event-queue/etc/Bass-Drum-1.wav | Bin 0 -> 221080 bytes event-queue/etc/Closed-Hi-Hat-1.wav | Bin 0 -> 13032 bytes event-queue/pom.xml | 42 ++++++ .../java/com/iluwatar/event/queue/App.java | 67 +++++++++ .../java/com/iluwatar/event/queue/Audio.java | 131 ++++++++++++++++++ .../com/iluwatar/event/queue/PlayMessage.java | 36 +++++ pom.xml | 1 + 8 files changed, 277 insertions(+) create mode 100644 event-queue/README.md create mode 100644 event-queue/etc/Bass-Drum-1.wav create mode 100644 event-queue/etc/Closed-Hi-Hat-1.wav create mode 100644 event-queue/pom.xml create mode 100644 event-queue/src/main/java/com/iluwatar/event/queue/App.java create mode 100644 event-queue/src/main/java/com/iluwatar/event/queue/Audio.java create mode 100644 event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java diff --git a/event-queue/README.md b/event-queue/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/event-queue/etc/Bass-Drum-1.wav b/event-queue/etc/Bass-Drum-1.wav new file mode 100644 index 0000000000000000000000000000000000000000..566181d942aa4542f36826d55161845f9ed0ad53 GIT binary patch literal 221080 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
  • 60JcG?;$VvR*l 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%0DPyWASwtTqG(=xxC$ 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 y;eWVa{^sco@Y8mk00;|V + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.16.0-SNAPSHOT + + event-queue + + + junit + junit + test + + + diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/App.java b/event-queue/src/main/java/com/iluwatar/event/queue/App.java new file mode 100644 index 000000000..a84027ecb --- /dev/null +++ b/event-queue/src/main/java/com/iluwatar/event/queue/App.java @@ -0,0 +1,67 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.event.queue; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +/** + * Event or message queues provide an asynchronous communications protocol, meaning that the sender + * and receiver of the message do not need to interact with the message queue at the same time. + * Events or messages placed onto the queue are stored until the recipient retrieves them. Event + * or message queues have implicit or explicit limits on the size of data that may be transmitted + * in a single message and the number of messages that may remain outstanding on the queue. + * A queue stores a series of notifications or requests in first-in, first-out order. + * Sending a notification enqueues the request and returns. The request processor then processes + * items from the queue at a later time. + */ +public class App { + /** + * Program entry point. + * + * @param args command line args + * @throws IOException when there is a problem with the audio file loading + * @throws UnsupportedAudioFileException when the loaded audio file is unsupported + */ + public static void main(String[] args) throws UnsupportedAudioFileException, IOException { + Audio.playSound(getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); + Audio.playSound(getAudioStream("./etc/Closed-Hi-Hat-1.wav"), -8.0f); + + System.out.println("Press Enter key to stop the program..."); + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + br.read(); + Audio.stopService(); + } + + public static AudioInputStream getAudioStream(String filePath) + throws UnsupportedAudioFileException, IOException { + return AudioSystem.getAudioInputStream(new File(filePath).getAbsoluteFile()); + } +} diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java new file mode 100644 index 000000000..a9f0c5a67 --- /dev/null +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -0,0 +1,131 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.event.queue; + +import java.io.IOException; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; + +/** + * This class implements the Event Queue pattern. + * @author mkuprivecz + * + */ +public class Audio { + + private static final int MAX_PENDING = 16; + + private static int headIndex; + + private static int tailIndex; + + private static Thread updateThread = null; + + private static PlayMessage[] pendingAudio = new PlayMessage[MAX_PENDING]; + + public static boolean isServiceRunning() { + return updateThread.isAlive(); + } + + /** + * This method stops the Update Method's thread. + */ + public static void stopService() { + if (updateThread != null) { + updateThread.interrupt(); + } + } + + /** + * Starts the thread for the Update Method pattern if it was not started previously. + * Also when the thread is is ready initializes the indexes of the queue + */ + public static void init() { + if (updateThread == null) { + updateThread = new Thread(new Runnable() { + public void run() { + while (!Thread.currentThread().isInterrupted()) { + Audio.update(); + } + } + }); + } + if (!updateThread.isAlive()) { + updateThread.start(); + headIndex = 0; + tailIndex = 0; + } + } + + /** + * This method adds a new audio into the queue. + * @param stream is the AudioInputStream for the method + * @param volume is the level of the audio's volume + */ + public static void playSound(AudioInputStream stream, float volume) { + init(); + // Walk the pending requests. + for (int i = headIndex; i != tailIndex; i = (i + 1) % MAX_PENDING) { + if (pendingAudio[i].stream == stream) { + // Use the larger of the two volumes. + pendingAudio[i].volume = Math.max(volume, pendingAudio[i].volume); + + // Don't need to enqueue. + return; + } + } + pendingAudio[tailIndex] = new PlayMessage(); + pendingAudio[tailIndex].stream = stream; + pendingAudio[tailIndex].volume = volume; + tailIndex = (tailIndex + 1) % MAX_PENDING; + } + + /** + * This method uses the Update Method pattern. + * It takes the audio from the queue and plays it + */ + public static void update() { + // If there are no pending requests, do nothing. + if (headIndex == tailIndex) { + return; + } + Clip clip = null; + try { + clip = AudioSystem.getClip(); + clip.open(pendingAudio[headIndex].stream); + } catch (LineUnavailableException e) { + System.err.println("Error occoured while loading the audio: The line is unavailable"); + e.printStackTrace(); + } catch (IOException e) { + System.err.println("Input/Output error while loading the audio"); + e.printStackTrace(); + } + clip.start(); + + headIndex++; + } +} diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java b/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java new file mode 100644 index 000000000..5d151e8d5 --- /dev/null +++ b/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.event.queue; + +import javax.sound.sampled.AudioInputStream; + +/** + * The Event Queue's queue will store the instances of this class. + * @author mkuprivecz + * + */ +public class PlayMessage { + AudioInputStream stream; + float volume; +} diff --git a/pom.xml b/pom.xml index 4b9740857..bca17e99a 100644 --- a/pom.xml +++ b/pom.xml @@ -133,6 +133,7 @@ promise page-object event-asynchronous + event-queue queue-load-leveling object-mother converter From 798aee47b325c8be5001373c44d4940f87f9b444 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Wed, 12 Apr 2017 18:59:43 +0300 Subject: [PATCH 230/492] Update ObjectPool.java --- .../src/main/java/com/iluwatar/object/pool/ObjectPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java index f502b86e2..df6e887b8 100644 --- a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java +++ b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java @@ -40,7 +40,7 @@ public abstract class ObjectPool { * Checkout object from pool */ public synchronized T checkOut() { - if (available.size() <= 0) { + if (available.isEmpty()) { available.add(create()); } T instance = available.iterator().next(); From ff8d854a8d4e0fce2303e1d151b2de98be9d2698 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 16 Apr 2017 06:51:10 +0100 Subject: [PATCH 231/492] #467 data-bus: README.md: clean up --- data-bus/README.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/data-bus/README.md b/data-bus/README.md index d65af8732..257192e25 100644 --- a/data-bus/README.md +++ b/data-bus/README.md @@ -1,14 +1,11 @@ ---- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/ -layout: pattern # layout must allways be pattern -title: Data Bus # the properly formatted title -folder: data-bus # the folder name in which this pattern lies -permalink: /patterns/data-bus/ # the permalink to the pattern, to keep this uniform please stick to /patterns/FOLDER/ +--- +layout: pattern +title: Data Bus +folder: data-bus +permalink: /patterns/data-bus/ -# both categories and tags are Yaml Lists -# you can either just pick one or write a list with '-'s -# usable categories and tags are listed here: https://github.com/iluwatar/java-design-patterns/blob/gh-pages/_config.yml -categories: Architectural # categories of the pattern -tags: # tags of the pattern +categories: Architectural +tags: - Java - Difficulty-Intermediate --- From 152b2762c3710902e1a08af7ffdca2b8d44c5388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Sat, 22 Apr 2017 17:16:38 +0200 Subject: [PATCH 232/492] read.me and the diagram is added --- event-queue/README.md | 29 ++++++++++++++ event-queue/etc/event-queue.urm.puml | 26 +++++++++++++ event-queue/etc/model.png | Bin 0 -> 10815 bytes event-queue/model.png | Bin 0 -> 10815 bytes event-queue/model.ucls | 36 ++++++++++++++++++ .../java/com/iluwatar/event/queue/Audio.java | 9 +---- 6 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 event-queue/etc/event-queue.urm.puml create mode 100644 event-queue/etc/model.png create mode 100644 event-queue/model.png create mode 100644 event-queue/model.ucls diff --git a/event-queue/README.md b/event-queue/README.md index e69de29bb..2129f8c69 100644 --- a/event-queue/README.md +++ b/event-queue/README.md @@ -0,0 +1,29 @@ +--- +layout: pattern +title: Event Queue +folder: event-queue +permalink: /patterns/event-queue/ +categories: Concurrency +tags: + - Java + - Difficulty Intermediate + - Queue +--- + +## Intent +Event Queue is a good pattern if You have a limited accesibility resource (for example: +Audio or Database), but You need to handle all the requests that want to use that. +It puts all the requests in a queue and process them asynchronously. +Gives the resource for the event when it is the next in the queue and in same time +removes it from the queue. + +![alt text](./etc/model.png "Event Queue") + +## Applicability +Use the Event Queue pattern when + +* You have a limited accesibility resource and the asynchronous process is acceptable to reach that + +## Credits + +* [Mihály Kuprivecz - Event Queue] diff --git a/event-queue/etc/event-queue.urm.puml b/event-queue/etc/event-queue.urm.puml new file mode 100644 index 000000000..e2aabee31 --- /dev/null +++ b/event-queue/etc/event-queue.urm.puml @@ -0,0 +1,26 @@ +@startuml +package com.iluwatar.event.queue { + class App { + + App() + + getAudioStream(filePath : String) : AudioInputStream {static} + + main(args : String[]) {static} + } + class Audio { + - MAX_PENDING : int {static} + - headIndex : int {static} + - pendingAudio : PlayMessage[] {static} + - tailIndex : int {static} + - updateThread : Thread {static} + + Audio() + + init() {static} + + playSound(stream : AudioInputStream, volume : float) {static} + + stopService() {static} + + update() {static} + } + class PlayMessage { + ~ stream : AudioInputStream + ~ volume : float + + PlayMessage() + } +} +@enduml \ No newline at end of file diff --git a/event-queue/etc/model.png b/event-queue/etc/model.png new file mode 100644 index 0000000000000000000000000000000000000000..8222dccbfabf674306accfe10e990d3adb12b43f GIT binary patch literal 10815 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 DNMN3U literal 0 HcmV?d00001 diff --git a/event-queue/model.png b/event-queue/model.png new file mode 100644 index 0000000000000000000000000000000000000000..8222dccbfabf674306accfe10e990d3adb12b43f GIT binary patch literal 10815 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 DNMN3U literal 0 HcmV?d00001 diff --git a/event-queue/model.ucls b/event-queue/model.ucls new file mode 100644 index 000000000..ed923014b --- /dev/null +++ b/event-queue/model.ucls @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index a9f0c5a67..e00cd375a 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -47,10 +47,6 @@ public class Audio { private static PlayMessage[] pendingAudio = new PlayMessage[MAX_PENDING]; - public static boolean isServiceRunning() { - return updateThread.isAlive(); - } - /** * This method stops the Update Method's thread. */ @@ -117,6 +113,8 @@ public class Audio { try { clip = AudioSystem.getClip(); clip.open(pendingAudio[headIndex].stream); + clip.start(); + headIndex++; } catch (LineUnavailableException e) { System.err.println("Error occoured while loading the audio: The line is unavailable"); e.printStackTrace(); @@ -124,8 +122,5 @@ public class Audio { System.err.println("Input/Output error while loading the audio"); e.printStackTrace(); } - clip.start(); - - headIndex++; } } From 9e7e8a64f6a2cec7b1f2d5e87c769f6896180c84 Mon Sep 17 00:00:00 2001 From: "Brandon D. McKay" Date: Wed, 26 Apr 2017 04:22:44 -0400 Subject: [PATCH 233/492] Fix incorrect URL --- event-driven-architecture/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event-driven-architecture/README.md b/event-driven-architecture/README.md index 0f698273b..a263defec 100644 --- a/event-driven-architecture/README.md +++ b/event-driven-architecture/README.md @@ -32,7 +32,7 @@ Use an Event-driven architecture when ## Credits -* [Event-driven architecture - Wikipedia](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained) +* [Event-driven architecture - Wikipedia](https://en.wikipedia.org/wiki/Event-driven_architecture) * [Fundamental Components of an Event-Driven Architecture](http://giocc.com/fundamental-components-of-an-event-driven-architecture.html) * [Real World Applications/Event Driven Applications](https://wiki.haskell.org/Real_World_Applications/Event_Driven_Applications) * [Event-driven architecture definition](http://searchsoa.techtarget.com/definition/event-driven-architecture) From 645e91ed23d436d5a535c88335d6d37f22189220 Mon Sep 17 00:00:00 2001 From: SrdjanPaunovic Date: Thu, 27 Apr 2017 13:58:58 +0200 Subject: [PATCH 234/492] first version of pattern without Tests --- extension-objects/pom.xml | 15 +++++ extension-objects/src/main/java/App.java | 59 +++++++++++++++++++ .../CommanderExtension.java | 7 +++ .../abstractextensions/SergeantExtension.java | 9 +++ .../abstractextensions/SoldierExtension.java | 8 +++ .../abstractextensions/UnitExtension.java | 7 +++ .../java/concreteextensions/Commander.java | 16 +++++ .../java/concreteextensions/Sergeant.java | 21 +++++++ .../main/java/concreteextensions/Soldier.java | 21 +++++++ .../src/main/java/units/CommanderUnit.java | 30 ++++++++++ .../src/main/java/units/SergeantUnit.java | 30 ++++++++++ .../src/main/java/units/SoldierUnit.java | 30 ++++++++++ .../src/main/java/units/Unit.java | 27 +++++++++ pom.xml | 1 + 14 files changed, 281 insertions(+) create mode 100644 extension-objects/pom.xml create mode 100644 extension-objects/src/main/java/App.java create mode 100644 extension-objects/src/main/java/abstractextensions/CommanderExtension.java create mode 100644 extension-objects/src/main/java/abstractextensions/SergeantExtension.java create mode 100644 extension-objects/src/main/java/abstractextensions/SoldierExtension.java create mode 100644 extension-objects/src/main/java/abstractextensions/UnitExtension.java create mode 100644 extension-objects/src/main/java/concreteextensions/Commander.java create mode 100644 extension-objects/src/main/java/concreteextensions/Sergeant.java create mode 100644 extension-objects/src/main/java/concreteextensions/Soldier.java create mode 100644 extension-objects/src/main/java/units/CommanderUnit.java create mode 100644 extension-objects/src/main/java/units/SergeantUnit.java create mode 100644 extension-objects/src/main/java/units/SoldierUnit.java create mode 100644 extension-objects/src/main/java/units/Unit.java diff --git a/extension-objects/pom.xml b/extension-objects/pom.xml new file mode 100644 index 000000000..afdf010a2 --- /dev/null +++ b/extension-objects/pom.xml @@ -0,0 +1,15 @@ + + + + java-design-patterns + com.iluwatar + 1.16.0-SNAPSHOT + + 4.0.0 + + extension-objects + + + \ No newline at end of file diff --git a/extension-objects/src/main/java/App.java b/extension-objects/src/main/java/App.java new file mode 100644 index 000000000..9aa934580 --- /dev/null +++ b/extension-objects/src/main/java/App.java @@ -0,0 +1,59 @@ +import abstractextensions.CommanderExtension; +import abstractextensions.SergeantExtension; +import abstractextensions.SoldierExtension; +import units.CommanderUnit; +import units.SergeantUnit; +import units.SoldierUnit; +import units.Unit; + +/** + * Created by Srdjan on 26-Apr-17. + */ +public class App { + + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { + + //Create 3 different units + Unit unit = new SoldierUnit("SoldierUnit1"); + Unit unit1 = new SergeantUnit("SergeantUnit1"); + Unit unit2 = new CommanderUnit("CommanderUnit1"); + + //check for each unit to have an extension + checkExtensionsForUnit(unit); + checkExtensionsForUnit(unit1); + checkExtensionsForUnit(unit2); + + } + + private static void checkExtensionsForUnit(Unit unit) { + //separate for better view + System.out.println(); + + SoldierExtension soldierExtension = (SoldierExtension) unit.getUnitExtension("SoldierExtension"); + SergeantExtension sergeantExtension = (SergeantExtension) unit.getUnitExtension("SergeantExtension"); + CommanderExtension commanderExtension = (CommanderExtension) unit.getUnitExtension("CommanderExtension"); + + if (soldierExtension != null) { + soldierExtension.soldierReady(); + } else { + System.out.println(unit.getName() + " without SoldierExtension"); + } + + if (sergeantExtension != null) { + sergeantExtension.sergeantReady(); + } else { + System.out.println(unit.getName() + " without SergeantExtension"); + } + + if (commanderExtension != null) { + // commanderExtension.sergeantReady(); + } else { + System.out.println(unit.getName() + " without CommanderExtension"); + } + } +} diff --git a/extension-objects/src/main/java/abstractextensions/CommanderExtension.java b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java new file mode 100644 index 000000000..aa716a3ae --- /dev/null +++ b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java @@ -0,0 +1,7 @@ +package abstractextensions; + +/** + * Created by Srdjan on 27-Apr-17. + */ +public interface CommanderExtension extends UnitExtension { +} diff --git a/extension-objects/src/main/java/abstractextensions/SergeantExtension.java b/extension-objects/src/main/java/abstractextensions/SergeantExtension.java new file mode 100644 index 000000000..dc7bbdc70 --- /dev/null +++ b/extension-objects/src/main/java/abstractextensions/SergeantExtension.java @@ -0,0 +1,9 @@ +package abstractextensions; + +/** + * Created by Srdjan on 27-Apr-17. + */ +public interface SergeantExtension extends UnitExtension { + + void sergeantReady(); +} diff --git a/extension-objects/src/main/java/abstractextensions/SoldierExtension.java b/extension-objects/src/main/java/abstractextensions/SoldierExtension.java new file mode 100644 index 000000000..1715811f8 --- /dev/null +++ b/extension-objects/src/main/java/abstractextensions/SoldierExtension.java @@ -0,0 +1,8 @@ +package abstractextensions; + +/** + * Created by Srdjan on 26-Apr-17. + */ +public interface SoldierExtension extends UnitExtension { + void soldierReady(); +} diff --git a/extension-objects/src/main/java/abstractextensions/UnitExtension.java b/extension-objects/src/main/java/abstractextensions/UnitExtension.java new file mode 100644 index 000000000..03c58d181 --- /dev/null +++ b/extension-objects/src/main/java/abstractextensions/UnitExtension.java @@ -0,0 +1,7 @@ +package abstractextensions; + +/** + * Created by Srdjan on 26-Apr-17. + */ +public interface UnitExtension { +} diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java new file mode 100644 index 000000000..3de4d124a --- /dev/null +++ b/extension-objects/src/main/java/concreteextensions/Commander.java @@ -0,0 +1,16 @@ +package concreteextensions; + +import abstractextensions.CommanderExtension; +import units.CommanderUnit; + +/** + * Created by Srdjan on 27-Apr-17. + */ +public class Commander implements CommanderExtension { + + private CommanderUnit unit; + + public Commander(CommanderUnit commanderUnit) { + this.unit = commanderUnit; + } +} diff --git a/extension-objects/src/main/java/concreteextensions/Sergeant.java b/extension-objects/src/main/java/concreteextensions/Sergeant.java new file mode 100644 index 000000000..b2d4485c3 --- /dev/null +++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java @@ -0,0 +1,21 @@ +package concreteextensions; + +import abstractextensions.SergeantExtension; +import units.SergeantUnit; + +/** + * Created by Srdjan on 27-Apr-17. + */ +public class Sergeant implements SergeantExtension { + + private SergeantUnit unit; + + public Sergeant(SergeantUnit sergeantUnit) { + this.unit = sergeantUnit; + } + + @Override + public void sergeantReady() { + System.out.println("[Sergeant] " + unit.getName() + " do command! "); + } +} diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java new file mode 100644 index 000000000..e2d11e244 --- /dev/null +++ b/extension-objects/src/main/java/concreteextensions/Soldier.java @@ -0,0 +1,21 @@ +package concreteextensions; + +import abstractextensions.SoldierExtension; +import units.SoldierUnit; + +/** + * Created by Srdjan on 26-Apr-17. + */ +public class Soldier implements SoldierExtension { + + private SoldierUnit unit; + + public Soldier(SoldierUnit soldierUnit) { + this.unit = soldierUnit; + } + + @Override + public void soldierReady() { + System.out.println("[Solider] " + unit.getName() + " do command"); + } +} diff --git a/extension-objects/src/main/java/units/CommanderUnit.java b/extension-objects/src/main/java/units/CommanderUnit.java new file mode 100644 index 000000000..67a0f9a06 --- /dev/null +++ b/extension-objects/src/main/java/units/CommanderUnit.java @@ -0,0 +1,30 @@ +package units; + +import abstractextensions.CommanderExtension; +import abstractextensions.UnitExtension; +import concreteextensions.Commander; + +/** + * Created by Srdjan on 27-Apr-17. + */ +public class CommanderUnit extends Unit { + + private CommanderExtension commanderExtension; + + public CommanderUnit(String name) { + super(name); + } + + @Override + public UnitExtension getUnitExtension(String extensionName) { + + if (extensionName.equals("CommanderExtension")) { + if (commanderExtension == null) { + commanderExtension = new Commander(this); + } + return commanderExtension; + } + + return super.getUnitExtension(extensionName); + } +} diff --git a/extension-objects/src/main/java/units/SergeantUnit.java b/extension-objects/src/main/java/units/SergeantUnit.java new file mode 100644 index 000000000..3188f7e4e --- /dev/null +++ b/extension-objects/src/main/java/units/SergeantUnit.java @@ -0,0 +1,30 @@ +package units; + +import abstractextensions.SergeantExtension; +import abstractextensions.UnitExtension; +import concreteextensions.Sergeant; + +/** + * Created by Srdjan on 27-Apr-17. + */ +public class SergeantUnit extends Unit { + + private SergeantExtension sergeantExtension; + + public SergeantUnit(String name) { + super(name); + } + + @Override + public UnitExtension getUnitExtension(String extensionName) { + + if (extensionName.equals("SergeantExtension")) { + if (sergeantExtension == null) { + sergeantExtension = new Sergeant(this); + } + return sergeantExtension; + } + + return super.getUnitExtension(extensionName); + } +} diff --git a/extension-objects/src/main/java/units/SoldierUnit.java b/extension-objects/src/main/java/units/SoldierUnit.java new file mode 100644 index 000000000..f96842465 --- /dev/null +++ b/extension-objects/src/main/java/units/SoldierUnit.java @@ -0,0 +1,30 @@ +package units; + +import abstractextensions.SoldierExtension; +import abstractextensions.UnitExtension; +import concreteextensions.Soldier; + +/** + * Created by Srdjan on 26-Apr-17. + */ +public class SoldierUnit extends Unit { + + private SoldierExtension soldierExtension; + + public SoldierUnit(String name) { + super(name); + } + + @Override + public UnitExtension getUnitExtension(String extensionName) { + + if (extensionName.equals("SoldierExtension")) { + if (soldierExtension == null) { + soldierExtension = new Soldier(this); + } + + return soldierExtension; + } + return super.getUnitExtension(extensionName); + } +} diff --git a/extension-objects/src/main/java/units/Unit.java b/extension-objects/src/main/java/units/Unit.java new file mode 100644 index 000000000..670c60aa8 --- /dev/null +++ b/extension-objects/src/main/java/units/Unit.java @@ -0,0 +1,27 @@ +package units; + +import abstractextensions.UnitExtension; + +/** + * Created by Srdjan on 26-Apr-17. + */ +public class Unit { + + private String name; + + public Unit(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public UnitExtension getUnitExtension(String extensionName) { + return null; + } +} diff --git a/pom.xml b/pom.xml index a45f0e1f3..dab143e8b 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,7 @@ converter guarded-suspension balking + extension-objects From 6e8eaf7593bf7ab21865ed035287bc00aa7262f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Fri, 28 Apr 2017 10:38:40 +0200 Subject: [PATCH 235/492] adding some test cases for the event queue --- .../java/com/iluwatar/event/queue/App.java | 12 +-- .../java/com/iluwatar/event/queue/Audio.java | 47 +++++++++-- .../com/iluwatar/event/queue/AudioTest.java | 77 +++++++++++++++++++ 3 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 event-queue/src/test/java/com/iluwatar/event/queue/AudioTest.java diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/App.java b/event-queue/src/main/java/com/iluwatar/event/queue/App.java index a84027ecb..ea107d6ca 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/App.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/App.java @@ -24,12 +24,9 @@ package com.iluwatar.event.queue; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; /** @@ -51,17 +48,12 @@ public class App { * @throws UnsupportedAudioFileException when the loaded audio file is unsupported */ public static void main(String[] args) throws UnsupportedAudioFileException, IOException { - Audio.playSound(getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); - Audio.playSound(getAudioStream("./etc/Closed-Hi-Hat-1.wav"), -8.0f); + Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); + Audio.playSound(Audio.getAudioStream("./etc/Closed-Hi-Hat-1.wav"), -8.0f); System.out.println("Press Enter key to stop the program..."); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br.read(); Audio.stopService(); } - - public static AudioInputStream getAudioStream(String filePath) - throws UnsupportedAudioFileException, IOException { - return AudioSystem.getAudioInputStream(new File(filePath).getAbsoluteFile()); - } } diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index e00cd375a..ecd535b49 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -23,12 +23,15 @@ package com.iluwatar.event.queue; +import java.io.File; import java.io.IOException; +import java.lang.Thread.State; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; /** * This class implements the Event Queue pattern. @@ -55,6 +58,17 @@ public class Audio { updateThread.interrupt(); } } + + /** + * This method stops the Update Method's thread. + * @return boolean + */ + public static boolean isServiceRunning() { + if (updateThread != null) { + return updateThread.isAlive(); + } + return false; + } /** * Starts the thread for the Update Method pattern if it was not started previously. @@ -86,17 +100,17 @@ public class Audio { init(); // Walk the pending requests. for (int i = headIndex; i != tailIndex; i = (i + 1) % MAX_PENDING) { - if (pendingAudio[i].stream == stream) { + if (getPendingAudio()[i].stream == stream) { // Use the larger of the two volumes. - pendingAudio[i].volume = Math.max(volume, pendingAudio[i].volume); + getPendingAudio()[i].volume = Math.max(volume, getPendingAudio()[i].volume); // Don't need to enqueue. return; } } - pendingAudio[tailIndex] = new PlayMessage(); - pendingAudio[tailIndex].stream = stream; - pendingAudio[tailIndex].volume = volume; + getPendingAudio()[tailIndex] = new PlayMessage(); + getPendingAudio()[tailIndex].stream = stream; + getPendingAudio()[tailIndex].volume = volume; tailIndex = (tailIndex + 1) % MAX_PENDING; } @@ -112,7 +126,7 @@ public class Audio { Clip clip = null; try { clip = AudioSystem.getClip(); - clip.open(pendingAudio[headIndex].stream); + clip.open(getPendingAudio()[headIndex].stream); clip.start(); headIndex++; } catch (LineUnavailableException e) { @@ -123,4 +137,25 @@ public class Audio { e.printStackTrace(); } } + + /** + * Returns the AudioInputStream of a file + * @param filePath is the path of the audio file + * @return AudioInputStream + * @throws UnsupportedAudioFileException when the audio file is not supported + * @throws IOException when the file is not readable + */ + public static AudioInputStream getAudioStream(String filePath) + throws UnsupportedAudioFileException, IOException { + return AudioSystem.getAudioInputStream(new File(filePath).getAbsoluteFile()); + } + + /** + * Returns with the message array of the queue + * @return PlayMessage[] + */ + public static PlayMessage[] getPendingAudio() { + return pendingAudio; + } + } diff --git a/event-queue/src/test/java/com/iluwatar/event/queue/AudioTest.java b/event-queue/src/test/java/com/iluwatar/event/queue/AudioTest.java new file mode 100644 index 000000000..4b3bd19ed --- /dev/null +++ b/event-queue/src/test/java/com/iluwatar/event/queue/AudioTest.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.event.queue; +import static org.junit.Assert.*; + +import java.io.IOException; + +import javax.sound.sampled.UnsupportedAudioFileException; + +import org.junit.Test; + +/** + * Testing the Audio service of the Queue + * @author mkuprivecz + * + */ +public class AudioTest { + + /** + * Test here that the playSound method works correctly + * @throws UnsupportedAudioFileException when the audio file is not supported + * @throws IOException when the file is not readable + * @throws InterruptedException when the test is interrupted externally + */ + @Test + public void testPlaySound() throws UnsupportedAudioFileException, IOException, InterruptedException { + Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); + // test that service is started + assertTrue(Audio.isServiceRunning()); + // adding a small pause to be sure that the sound is ended + Thread.sleep(5000); + // test that service is finished + assertFalse(!Audio.isServiceRunning()); + } + + /** + * Test here that the Queue + * @throws UnsupportedAudioFileException when the audio file is not supported + * @throws IOException when the file is not readable + * @throws InterruptedException when the test is interrupted externally + */ + @Test + public void testQueue() throws UnsupportedAudioFileException, IOException, InterruptedException { + Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); + Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); + Audio.playSound(Audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); + assertTrue(Audio.getPendingAudio().length > 0); + // test that service is started + assertTrue(Audio.isServiceRunning()); + // adding a small pause to be sure that the sound is ended + Thread.sleep(10000); + // test that service is finished + assertFalse(!Audio.isServiceRunning()); + } + +} From 44401988d13177ed4b3d86e8b93540f158ef8b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Fri, 28 Apr 2017 11:32:35 +0200 Subject: [PATCH 236/492] pom.xml fixes --- event-queue/pom.xml | 11 +++--- .../java/com/iluwatar/event/queue/Audio.java | 1 - pom.xml | 38 +++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/event-queue/pom.xml b/event-queue/pom.xml index 16ee381b3..fc857b425 100644 --- a/event-queue/pom.xml +++ b/event-queue/pom.xml @@ -1,4 +1,4 @@ - + - + 4.0.0 - com.iluwatar java-design-patterns + com.iluwatar 1.16.0-SNAPSHOT event-queue @@ -39,4 +40,4 @@ test - + \ No newline at end of file diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index ecd535b49..9175eeffa 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -25,7 +25,6 @@ package com.iluwatar.event.queue; import java.io.File; import java.io.IOException; -import java.lang.Thread.State; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; diff --git a/pom.xml b/pom.xml index bca17e99a..c9b7a2faf 100644 --- a/pom.xml +++ b/pom.xml @@ -122,7 +122,7 @@ factory-kit feature-toggle value-object - module + module monad mute-idiom mutex @@ -133,7 +133,7 @@ promise page-object event-asynchronous - event-queue + event-queue queue-load-leveling object-mother converter @@ -302,23 +302,23 @@ - - - com.github.markusmo3.urm - - - urm-maven-plugin - - - [1.4.1,) - - - map - - - - - + + + com.github.markusmo3.urm + + + urm-maven-plugin + + + [1.4.1,) + + + map + + + + + From a1c51313040643a3ec6cc92ab45adf0df68282c5 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Fri, 28 Apr 2017 12:59:09 +0300 Subject: [PATCH 237/492] Add files via upload --- .../injection/AdvancedSorceress.java | 45 ++++++++++++++++ .../iluwatar/dependency/injection/App.java | 51 ++++++++++--------- 2 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java new file mode 100644 index 000000000..4a952e952 --- /dev/null +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java @@ -0,0 +1,45 @@ +package com.iluwatar.dependency.injection; + +/** + * The MIT License + * Copyright (c) 2014-2017 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. + */ + + +/** + * + * AdvancedSorceress implements inversion of control. It depends on abstraction that can be injected + * through its setter. + * + */ +public class AdvancedSorceress implements Wizard { + + private Tobacco tobacco; + + public void setTobacco(Tobacco tobacco) { + this.tobacco = tobacco; + } + + @Override + public void smoke() { + tobacco.smoke(this); + } +} diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java index c7b9d6fb6..8723f9b4f 100644 --- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java @@ -1,17 +1,17 @@ /** * The MIT License * Copyright (c) 2014-2016 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 @@ -26,7 +26,7 @@ import com.google.inject.Guice; import com.google.inject.Injector; /** - * + * * Dependency Injection pattern deals with how objects handle their dependencies. The pattern * implements so called inversion of control principle. Inversion of control has two specific rules: * - High-level modules should not depend on low-level modules. Both should depend on abstractions. @@ -36,32 +36,37 @@ import com.google.inject.Injector; * naive implementation violating the inversion of control principle. It depends directly on a * concrete implementation which cannot be changed. *

    - * The second wizard ({@link AdvancedWizard}) is more flexible. It does not depend on any concrete - * implementation but abstraction. It utilizes Dependency Injection pattern allowing its - * {@link Tobacco} dependency to be injected through its constructor. This way, handling the - * dependency is no longer the wizard's responsibility. It is resolved outside the wizard class. + * The second and third wizards({@link AdvancedWizard} and {@link AdvancedSorceress}) are more flexible. + * They do not depend on any concrete implementation but abstraction. They utilizes Dependency Injection + * pattern allowing their {@link Tobacco} dependency to be injected through constructor ({@link AdvancedWizard}) + * or setter ({@link AdvancedSorceress}). This way, handling the dependency is no longer the wizard's + * responsibility. It is resolved outside the wizard class. *

    - * The third example takes the pattern a step further. It uses Guice framework for Dependency + * The fourth example takes the pattern a step further. It uses Guice framework for Dependency * Injection. {@link TobaccoModule} binds a concrete implementation to abstraction. Injector is then * used to create {@link GuiceWizard} object with correct dependencies. * */ public class App { - /** - * Program entry point - * - * @param args command line args - */ - public static void main(String[] args) { - SimpleWizard simpleWizard = new SimpleWizard(); - simpleWizard.smoke(); + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { + SimpleWizard simpleWizard = new SimpleWizard(); + simpleWizard.smoke(); - AdvancedWizard advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); - advancedWizard.smoke(); + AdvancedWizard advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); + advancedWizard.smoke(); - Injector injector = Guice.createInjector(new TobaccoModule()); - GuiceWizard guiceWizard = injector.getInstance(GuiceWizard.class); - guiceWizard.smoke(); - } + AdvancedSorceress advancedSorceress = new AdvancedSorceress(); + advancedSorceress.setTobacco(new SecondBreakfastTobacco()); + advancedSorceress.smoke(); + + Injector injector = Guice.createInjector(new TobaccoModule()); + GuiceWizard guiceWizard = injector.getInstance(GuiceWizard.class); + guiceWizard.smoke(); + } } From ccfb6709c7c9c76ee228fe42ffc2699bf933298d Mon Sep 17 00:00:00 2001 From: kapinuss Date: Fri, 28 Apr 2017 13:00:01 +0300 Subject: [PATCH 238/492] Add files via upload --- .../injection/AdvancedSorceressTest.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java new file mode 100644 index 000000000..eadb0b931 --- /dev/null +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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. + *

    + * Marker interface vs annotation + * Marker interfaces and marker annotations both have their uses, + * neither of them is obsolete or always better then the other one. + * If you want to define a type that does not have any new methods associated with it, + * a marker interface is the way to go. + * If you want to mark program elements other than classes and interfaces, + * to allow for the possibility of adding more information to the marker in the future, + * or to fit the marker into a framework that already makes heavy use of annotation types, + * then a marker annotation is the correct choice */ public class App { + + /** + * Program entry point + * + * @param args command line args + */ public static void main(String[] args) { + Guard guard = new Guard(); + Thief thief = new Thief(); if (guard instanceof Permission) { guard.enter(); + } else { + System.out.println("You have no permission to enter, please leave this area"); + } + + if (thief instanceof Permission) { + thief.steal(); + } else { + thief.doNothing(); } } } diff --git a/marker/src/main/java/Thief.java b/marker/src/main/java/Thief.java new file mode 100644 index 000000000..33eac5aca --- /dev/null +++ b/marker/src/main/java/Thief.java @@ -0,0 +1,12 @@ +/** + * Created by Alexis on 02-May-17. + */ +public class Thief { + protected static void steal() { + System.out.println("Steal valuable items"); + } + + protected static void doNothing() { + System.out.println("Pretend nothing happened and just leave"); + } +} diff --git a/marker/src/test/java/AppTest.java b/marker/src/test/java/AppTest.java new file mode 100644 index 000000000..615a3c910 --- /dev/null +++ b/marker/src/test/java/AppTest.java @@ -0,0 +1,17 @@ +/** + * Created by Alexis on 01-May-17. + */ + +import org.junit.Test; + +/** + * Application test + */ +public class AppTest { + + @Test + public void test() { + String[] args = {}; + App.main(args); + } +} diff --git a/marker/src/test/java/GuardTest.java b/marker/src/test/java/GuardTest.java new file mode 100644 index 000000000..459447367 --- /dev/null +++ b/marker/src/test/java/GuardTest.java @@ -0,0 +1,16 @@ +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; + +/** + * Created by Alexis on 02-May-17. + */ +public class GuardTest { + + @Test + public void testGuard() { + Guard guard = new Guard(); + assertThat(guard, instanceOf(Permission.class)); + } +} diff --git a/marker/src/test/java/ThiefTest.java b/marker/src/test/java/ThiefTest.java new file mode 100644 index 000000000..37409ecb3 --- /dev/null +++ b/marker/src/test/java/ThiefTest.java @@ -0,0 +1,15 @@ +/** + * Created by Alexis on 02-May-17. + */ + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; + +public class ThiefTest { + @Test + public void testGuard() { + Thief thief = new Thief(); + assertFalse(thief instanceof Permission); + } +} From c92a8daeda2997222b3c02bdc6bd9986f6cd8f1e Mon Sep 17 00:00:00 2001 From: SrdjanPaunovic Date: Wed, 3 May 2017 17:59:54 +0200 Subject: [PATCH 248/492] Class diagram & fix relation between units --- extension-objects/etc/extension_obj.png | Bin 0 -> 38018 bytes extension-objects/etc/extension_obj.ucls | 180 ++++++++++++++++++ extension-objects/etc/extension_obj1.png | Bin 0 -> 14390 bytes .../src/main/java/units/CommanderUnit.java | 8 +- .../src/main/java/units/SergeantUnit.java | 8 +- .../src/main/java/units/SoldierUnit.java | 8 +- .../src/main/java/units/Unit.java | 1 + .../src/test/java/units/UnitTest.java | 2 - 8 files changed, 190 insertions(+), 17 deletions(-) create mode 100644 extension-objects/etc/extension_obj.png create mode 100644 extension-objects/etc/extension_obj.ucls create mode 100644 extension-objects/etc/extension_obj1.png diff --git a/extension-objects/etc/extension_obj.png b/extension-objects/etc/extension_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b750e9deddee833ccbea50b0d789390060e986 GIT binary patch literal 38018 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 T5LYt!3F3OX`njxgN@xNAEupb; literal 0 HcmV?d00001 diff --git a/extension-objects/etc/extension_obj.ucls b/extension-objects/etc/extension_obj.ucls new file mode 100644 index 000000000..9471caa83 --- /dev/null +++ b/extension-objects/etc/extension_obj.ucls @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extension-objects/etc/extension_obj1.png b/extension-objects/etc/extension_obj1.png new file mode 100644 index 0000000000000000000000000000000000000000..e3115661f4aa51559d553c7ca27ad9da97300336 GIT binary patch literal 14390 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 Z<{Bk;ux2a Date: Wed, 3 May 2017 19:48:29 +0200 Subject: [PATCH 249/492] Added README.md --- marker/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 marker/README.md diff --git a/marker/README.md b/marker/README.md new file mode 100644 index 000000000..dbca4ca83 --- /dev/null +++ b/marker/README.md @@ -0,0 +1,30 @@ +--- +layout: pattern +title: Marker Interface +folder: marker +permalink: /patterns/marker/ +categories: Design +tags: + - Java + - Difficulty-Beginner +--- + +## Intent +Using empy interfaces as markers to distinguish special treated objects. + +![alt text](./marker/etc/MarkerDiagram.png "Marker Interface") + +## Applicability +Use the Marker Interface pattern when + +* you want to identify the special objects from normal objects +* define a type that is implemented by instances of the marked class, marker annotations can not do that + +## Real world examples + +* [javase.7.docs.api.java.io.Serializable](https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html) +* [javase.7.docs.api.java.lang.Cloneable](https://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html) + +## Credits + +* [Effective Java 2nd Edition by Joshua Bloch](https://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683) From be3f4dce50253de29632c2ba98328e4230a57f82 Mon Sep 17 00:00:00 2001 From: 4lexis Date: Wed, 3 May 2017 19:49:25 +0200 Subject: [PATCH 250/492] Update Picture --- marker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marker/README.md b/marker/README.md index dbca4ca83..8ff25100a 100644 --- a/marker/README.md +++ b/marker/README.md @@ -12,7 +12,7 @@ tags: ## Intent Using empy interfaces as markers to distinguish special treated objects. -![alt text](./marker/etc/MarkerDiagram.png "Marker Interface") +![alt text](./etc/MarkerDiagram.png "Marker Interface") ## Applicability Use the Marker Interface pattern when From 6e0b3e37ea10e26241cb4e5d56c2106de37a19cd Mon Sep 17 00:00:00 2001 From: Aleksandar Dudukovic Date: Wed, 3 May 2017 19:57:14 +0200 Subject: [PATCH 251/492] updated pom.xml --- marker/pom.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/marker/pom.xml b/marker/pom.xml index 74969d2eb..c7345d8ee 100644 --- a/marker/pom.xml +++ b/marker/pom.xml @@ -1,4 +1,24 @@ + + From 66c6f30c1c31a5dc09d6b7a14e1b7c96de4effd0 Mon Sep 17 00:00:00 2001 From: 4lexis Date: Wed, 3 May 2017 20:34:27 +0200 Subject: [PATCH 252/492] #567 Updated pom.xml --- marker/pom.xml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/marker/pom.xml b/marker/pom.xml index 74969d2eb..ceab669aa 100644 --- a/marker/pom.xml +++ b/marker/pom.xml @@ -1,4 +1,23 @@ + @@ -27,4 +46,4 @@ - \ No newline at end of file + From 34b09c75ec3e1c6369e2c837896259bc6885934d Mon Sep 17 00:00:00 2001 From: 4lexis Date: Wed, 3 May 2017 20:51:51 +0200 Subject: [PATCH 253/492] #567 added .gitignore --- marker/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 marker/.gitignore diff --git a/marker/.gitignore b/marker/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/marker/.gitignore @@ -0,0 +1 @@ +/target/ From 0687a3f9f8b3405b4a09f0383cefd353f48ef082 Mon Sep 17 00:00:00 2001 From: SrdjanPaunovic Date: Wed, 3 May 2017 21:40:54 +0200 Subject: [PATCH 254/492] #541 pom.xml fix align --- extension-objects/pom.xml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/extension-objects/pom.xml b/extension-objects/pom.xml index 77f6ccfa2..4c0b0a230 100644 --- a/extension-objects/pom.xml +++ b/extension-objects/pom.xml @@ -2,20 +2,20 @@ - - java-design-patterns - com.iluwatar - 1.16.0-SNAPSHOT - - 4.0.0 - - extension-objects - - - junit - junit - - + + java-design-patterns + com.iluwatar + 1.16.0-SNAPSHOT + + 4.0.0 + extension-objects + + + junit + junit + test + + From 6ecf994258d1f042121f910d639b887f8934a958 Mon Sep 17 00:00:00 2001 From: Aleksandar Dudukovic Date: Wed, 3 May 2017 21:42:15 +0200 Subject: [PATCH 255/492] #567 pom.xml align fix --- marker/pom.xml | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/marker/pom.xml b/marker/pom.xml index ceab669aa..ab92bdbc6 100644 --- a/marker/pom.xml +++ b/marker/pom.xml @@ -21,29 +21,29 @@ - - java-design-patterns - com.iluwatar - 1.16.0-SNAPSHOT - - 4.0.0 + + java-design-patterns + com.iluwatar + 1.16.0-SNAPSHOT + + 4.0.0 - marker - - - org.junit.jupiter - junit-jupiter-api - RELEASE - - - junit - junit - - - junit - junit - - + marker + + + org.junit.jupiter + junit-jupiter-api + RELEASE + + + junit + junit + + + junit + junit + + From 08c4202852b1b1a157fa77620f0d66d343ffe9c5 Mon Sep 17 00:00:00 2001 From: SrdjanPaunovic Date: Wed, 3 May 2017 22:08:04 +0200 Subject: [PATCH 256/492] #541 fix checkstyle errors --- execute-around/pom.xml | 4 +++- extension-objects/src/main/java/units/CommanderUnit.java | 1 - extension-objects/src/main/java/units/SergeantUnit.java | 1 - extension-objects/src/main/java/units/SoldierUnit.java | 1 - extension-objects/src/test/java/AppTest.java | 2 -- .../src/test/java/concreteextensions/CommanderTest.java | 2 -- .../src/test/java/concreteextensions/SergeantTest.java | 2 -- .../src/test/java/concreteextensions/SoldierTest.java | 2 -- .../src/test/java/units/CommanderUnitTest.java | 5 +++-- .../src/test/java/units/SergeantUnitTest.java | 5 +++-- .../src/test/java/units/SoldierUnitTest.java | 5 +++-- extension-objects/src/test/java/units/UnitTest.java | 9 ++++----- 12 files changed, 16 insertions(+), 23 deletions(-) diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 765b52846..59f9b3dea 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -23,7 +23,9 @@ THE SOFTWARE. --> - 4.0.0 diff --git a/extension-objects/src/main/java/units/CommanderUnit.java b/extension-objects/src/main/java/units/CommanderUnit.java index 836d29487..a5ed60a76 100644 --- a/extension-objects/src/main/java/units/CommanderUnit.java +++ b/extension-objects/src/main/java/units/CommanderUnit.java @@ -1,6 +1,5 @@ package units; -import abstractextensions.CommanderExtension; import abstractextensions.UnitExtension; import concreteextensions.Commander; diff --git a/extension-objects/src/main/java/units/SergeantUnit.java b/extension-objects/src/main/java/units/SergeantUnit.java index d1a477ee8..876a50db5 100644 --- a/extension-objects/src/main/java/units/SergeantUnit.java +++ b/extension-objects/src/main/java/units/SergeantUnit.java @@ -1,6 +1,5 @@ package units; -import abstractextensions.SergeantExtension; import abstractextensions.UnitExtension; import concreteextensions.Sergeant; diff --git a/extension-objects/src/main/java/units/SoldierUnit.java b/extension-objects/src/main/java/units/SoldierUnit.java index 749e3aa8d..9e566796b 100644 --- a/extension-objects/src/main/java/units/SoldierUnit.java +++ b/extension-objects/src/main/java/units/SoldierUnit.java @@ -1,6 +1,5 @@ package units; -import abstractextensions.SoldierExtension; import abstractextensions.UnitExtension; import concreteextensions.Soldier; diff --git a/extension-objects/src/test/java/AppTest.java b/extension-objects/src/test/java/AppTest.java index 88ba70da9..287ffc131 100644 --- a/extension-objects/src/test/java/AppTest.java +++ b/extension-objects/src/test/java/AppTest.java @@ -1,7 +1,5 @@ import org.junit.Test; -import static org.junit.Assert.*; - /** * Created by Srdjan on 03-May-17. */ diff --git a/extension-objects/src/test/java/concreteextensions/CommanderTest.java b/extension-objects/src/test/java/concreteextensions/CommanderTest.java index a5ac7b506..82079c69a 100644 --- a/extension-objects/src/test/java/concreteextensions/CommanderTest.java +++ b/extension-objects/src/test/java/concreteextensions/CommanderTest.java @@ -3,8 +3,6 @@ package concreteextensions; import org.junit.Test; import units.CommanderUnit; -import static org.junit.Assert.*; - /** * Created by Srdjan on 03-May-17. */ diff --git a/extension-objects/src/test/java/concreteextensions/SergeantTest.java b/extension-objects/src/test/java/concreteextensions/SergeantTest.java index 163d5c1fc..7b29057f6 100644 --- a/extension-objects/src/test/java/concreteextensions/SergeantTest.java +++ b/extension-objects/src/test/java/concreteextensions/SergeantTest.java @@ -3,8 +3,6 @@ package concreteextensions; import org.junit.Test; import units.SergeantUnit; -import static org.junit.Assert.*; - /** * Created by Srdjan on 03-May-17. */ diff --git a/extension-objects/src/test/java/concreteextensions/SoldierTest.java b/extension-objects/src/test/java/concreteextensions/SoldierTest.java index dde222d61..02a3144c2 100644 --- a/extension-objects/src/test/java/concreteextensions/SoldierTest.java +++ b/extension-objects/src/test/java/concreteextensions/SoldierTest.java @@ -3,8 +3,6 @@ package concreteextensions; import org.junit.Test; import units.SoldierUnit; -import static org.junit.Assert.*; - /** * Created by Srdjan on 03-May-17. */ diff --git a/extension-objects/src/test/java/units/CommanderUnitTest.java b/extension-objects/src/test/java/units/CommanderUnitTest.java index 1ec498d91..75bf5f4fc 100644 --- a/extension-objects/src/test/java/units/CommanderUnitTest.java +++ b/extension-objects/src/test/java/units/CommanderUnitTest.java @@ -3,7 +3,8 @@ package units; import abstractextensions.CommanderExtension; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * Created by Srdjan on 03-May-17. @@ -16,7 +17,7 @@ public class CommanderUnitTest { assertNull(unit.getUnitExtension("SoldierExtension")); assertNull(unit.getUnitExtension("SergeantExtension")); - assertNotNull((CommanderExtension)unit.getUnitExtension("CommanderExtension")); + assertNotNull((CommanderExtension) unit.getUnitExtension("CommanderExtension")); } } \ No newline at end of file diff --git a/extension-objects/src/test/java/units/SergeantUnitTest.java b/extension-objects/src/test/java/units/SergeantUnitTest.java index 8fe62298c..af2eca7cc 100644 --- a/extension-objects/src/test/java/units/SergeantUnitTest.java +++ b/extension-objects/src/test/java/units/SergeantUnitTest.java @@ -3,7 +3,8 @@ package units; import abstractextensions.SergeantExtension; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * Created by Srdjan on 03-May-17. @@ -15,7 +16,7 @@ public class SergeantUnitTest { final Unit unit = new SergeantUnit("SergeantUnitName"); assertNull(unit.getUnitExtension("SoldierExtension")); - assertNotNull((SergeantExtension)unit.getUnitExtension("SergeantExtension")); + assertNotNull((SergeantExtension) unit.getUnitExtension("SergeantExtension")); assertNull(unit.getUnitExtension("CommanderExtension")); } diff --git a/extension-objects/src/test/java/units/SoldierUnitTest.java b/extension-objects/src/test/java/units/SoldierUnitTest.java index 8d1fe5667..19b0c2923 100644 --- a/extension-objects/src/test/java/units/SoldierUnitTest.java +++ b/extension-objects/src/test/java/units/SoldierUnitTest.java @@ -3,7 +3,8 @@ package units; import abstractextensions.SoldierExtension; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * Created by Srdjan on 03-May-17. @@ -14,7 +15,7 @@ public class SoldierUnitTest { final Unit unit = new SoldierUnit("SoldierUnitName"); - assertNotNull((SoldierExtension)unit.getUnitExtension("SoldierExtension")); + assertNotNull((SoldierExtension) unit.getUnitExtension("SoldierExtension")); assertNull(unit.getUnitExtension("SergeantExtension")); assertNull(unit.getUnitExtension("CommanderExtension")); diff --git a/extension-objects/src/test/java/units/UnitTest.java b/extension-objects/src/test/java/units/UnitTest.java index 42cb1037f..773b485ce 100644 --- a/extension-objects/src/test/java/units/UnitTest.java +++ b/extension-objects/src/test/java/units/UnitTest.java @@ -1,10 +1,9 @@ package units; -import org.junit.After; -import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; /** * Created by Srdjan on 03-May-17. @@ -15,11 +14,11 @@ public class UnitTest { public void testConstGetSet() throws Exception { final String name = "testName"; final Unit unit = new Unit(name); - assertEquals(name,unit.getName()); + assertEquals(name, unit.getName()); final String newName = "newName"; unit.setName(newName); - assertEquals(newName,unit.getName()); + assertEquals(newName, unit.getName()); assertNull(unit.getUnitExtension("")); From 1abd96a9c8f9a07bee0048b43d4b09f0391dc5f9 Mon Sep 17 00:00:00 2001 From: Aleksandar Dudukovic Date: Wed, 3 May 2017 22:09:47 +0200 Subject: [PATCH 257/492] #567 checkstyle fix --- marker/src/test/java/ThiefTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/marker/src/test/java/ThiefTest.java b/marker/src/test/java/ThiefTest.java index 37409ecb3..bcc862803 100644 --- a/marker/src/test/java/ThiefTest.java +++ b/marker/src/test/java/ThiefTest.java @@ -1,11 +1,10 @@ -/** - * Created by Alexis on 02-May-17. - */ - import org.junit.Test; import static org.junit.Assert.assertFalse; +/** + * Created by Alexis on 02-May-17. + */ public class ThiefTest { @Test public void testGuard() { From 6857486f27c356da8c7770c27cc5ea5013bde011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sr=C4=91an=20Paunovi=C4=87?= Date: Thu, 4 May 2017 12:33:25 +0200 Subject: [PATCH 258/492] #541 Create README.md file --- extension-objects/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 extension-objects/README.md diff --git a/extension-objects/README.md b/extension-objects/README.md new file mode 100644 index 000000000..e345952ed --- /dev/null +++ b/extension-objects/README.md @@ -0,0 +1,28 @@ +--- +layout: pattern +title: Extension objects +folder: extension-objects +permalink: /patterns/extension-objects/ +categories: Behavioral +tags: + - Java + - Difficulty-Intermediate +--- + +## Intent +Anticipate that an object’s interface needs to be extended in the future. Additional +interfaces are defined by extension objects. + +![alt text](./etc/extension_obj1.png "Extension objects") + +## Applicability +Use the Extension Objects pattern when: + +* you need to support the addition of new or unforeseen interfaces to existing classes and you don't want to impact clients that don't need this new interface. Extension Objects lets you keep related operations together by defining them in a separate class +* a class representing a key abstraction plays different roles for different clients. The number of roles the class can play should be open-ended. There is a need to preserve the key abstraction itself. For example, a customer object is still a customer object even if different subsystems view it differently. +* a class should be extensible with new behavior without subclassing from it. + +## Real world examples + +* [OpenDoc](https://en.wikipedia.org/wiki/OpenDoc) +* [Object Linking and Embedding](https://en.wikipedia.org/wiki/Object_Linking_and_Embedding) From fb26d42b51300b1665dc3d792c6d12e7e3eff5a6 Mon Sep 17 00:00:00 2001 From: prafful1 Date: Sun, 7 May 2017 13:28:54 +0530 Subject: [PATCH 259/492] Few additions in README Added few more points in applicability and also some use cases and consequences. --- abstract-factory/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/abstract-factory/README.md b/abstract-factory/README.md index a3881b893..f153c1202 100644 --- a/abstract-factory/README.md +++ b/abstract-factory/README.md @@ -27,6 +27,22 @@ Use the Abstract Factory pattern when * a system should be configured with one of multiple families of products * a family of related product objects is designed to be used together, and you need to enforce this constraint * you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations +* the lifetime of the dependency is conceptually shorter than the lifetime of the consumer. +* you need a run-time value to construct a particular dependency +* you want to decide which product to call from a family at runtime. +* you need to supply one or more parameters only known at run-time before you can resolve a dependency. + +## Use Cases: + +* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime. +* Unit test case writing becomes much easier + +## Consequences: + +* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time. + + + ## Real world examples From 857902ab95f4c4137fb93976c9c664820e7b27af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Thu, 11 May 2017 21:41:25 +0200 Subject: [PATCH 260/492] compatibility fix When the system is not capable to play the sound, do not throw exception, just log it. For example on Linux there are several issues to play sound and there are no workarounds for that :( --- event-queue/src/main/java/com/iluwatar/event/queue/Audio.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index b482acca1..7c2f04d09 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -132,16 +132,18 @@ public class Audio { } Clip clip = null; try { + headIndex++; clip = AudioSystem.getClip(); clip.open(getPendingAudio()[headIndex].stream); clip.start(); - headIndex++; } catch (LineUnavailableException e) { System.err.println("Error occoured while loading the audio: The line is unavailable"); e.printStackTrace(); } catch (IOException e) { System.err.println("Input/Output error while loading the audio"); e.printStackTrace(); + } catch (IllegalArgumentException e) { + System.err.println("The system doesn't support the sound: " + e.getMessage()); } } From 0546223bbaae2cc62a9d254daa6cb2a02a78eaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Thu, 11 May 2017 21:44:07 +0200 Subject: [PATCH 261/492] quick fix --- event-queue/src/main/java/com/iluwatar/event/queue/Audio.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index 7c2f04d09..7554464dd 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -132,9 +132,10 @@ public class Audio { } Clip clip = null; try { + AudioInputStream audioStream = getPendingAudio()[headIndex].stream; headIndex++; clip = AudioSystem.getClip(); - clip.open(getPendingAudio()[headIndex].stream); + clip.open(audioStream); clip.start(); } catch (LineUnavailableException e) { System.err.println("Error occoured while loading the audio: The line is unavailable"); From fe1e45bd693913e3f95f87b5e2361db69d1126af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Mon, 15 May 2017 10:40:12 +0200 Subject: [PATCH 262/492] some fixes --- event-queue/README.md | 2 +- event-queue/{ => etc}/model.ucls | 0 event-queue/model.png | Bin 10815 -> 0 bytes .../java/com/iluwatar/event/queue/Audio.java | 10 +++---- .../com/iluwatar/event/queue/PlayMessage.java | 27 ++++++++++++++++-- 5 files changed, 30 insertions(+), 9 deletions(-) rename event-queue/{ => etc}/model.ucls (100%) delete mode 100644 event-queue/model.png diff --git a/event-queue/README.md b/event-queue/README.md index 2129f8c69..35fdac45c 100644 --- a/event-queue/README.md +++ b/event-queue/README.md @@ -26,4 +26,4 @@ Use the Event Queue pattern when ## Credits -* [Mihály Kuprivecz - Event Queue] +* [Mihaly Kuprivecz - Event Queue] (http://gameprogrammingpatterns.com/event-queue.html) diff --git a/event-queue/model.ucls b/event-queue/etc/model.ucls similarity index 100% rename from event-queue/model.ucls rename to event-queue/etc/model.ucls diff --git a/event-queue/model.png b/event-queue/model.png deleted file mode 100644 index 8222dccbfabf674306accfe10e990d3adb12b43f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10815 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 DNMN3U diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index 7554464dd..f8f1b1e3c 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -107,17 +107,15 @@ public class Audio { init(); // Walk the pending requests. for (int i = headIndex; i != tailIndex; i = (i + 1) % MAX_PENDING) { - if (getPendingAudio()[i].stream == stream) { + if (getPendingAudio()[i].getStream() == stream) { // Use the larger of the two volumes. - getPendingAudio()[i].volume = Math.max(volume, getPendingAudio()[i].volume); + getPendingAudio()[i].setVolume(Math.max(volume, getPendingAudio()[i].getVolume())); // Don't need to enqueue. return; } } - getPendingAudio()[tailIndex] = new PlayMessage(); - getPendingAudio()[tailIndex].stream = stream; - getPendingAudio()[tailIndex].volume = volume; + getPendingAudio()[tailIndex] = new PlayMessage(stream, volume); tailIndex = (tailIndex + 1) % MAX_PENDING; } @@ -132,7 +130,7 @@ public class Audio { } Clip clip = null; try { - AudioInputStream audioStream = getPendingAudio()[headIndex].stream; + AudioInputStream audioStream = getPendingAudio()[headIndex].getStream(); headIndex++; clip = AudioSystem.getClip(); clip.open(audioStream); diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java b/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java index 5d151e8d5..5ced2e3b3 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/PlayMessage.java @@ -31,6 +31,29 @@ import javax.sound.sampled.AudioInputStream; * */ public class PlayMessage { - AudioInputStream stream; - float volume; + + private AudioInputStream stream; + + private float volume; + + public PlayMessage(AudioInputStream stream, float volume) { + setStream(stream); + setVolume(volume); + } + + public AudioInputStream getStream() { + return stream; + } + + private void setStream(AudioInputStream stream) { + this.stream = stream; + } + + public float getVolume() { + return volume; + } + + public void setVolume(float volume) { + this.volume = volume; + } } From 167a43f72e5132d51462a268ab9d690f36fdec45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Mon, 15 May 2017 11:04:41 +0200 Subject: [PATCH 263/492] updated model.png --- event-queue/etc/model.png | Bin 10815 -> 17218 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/event-queue/etc/model.png b/event-queue/etc/model.png index 8222dccbfabf674306accfe10e990d3adb12b43f..45620e6f69a195b637d0840250bbdf976b9e356a 100644 GIT binary patch literal 17218 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 DNMN3U From 09aa44ddcb2b42d601015088853cbb2d069b56d3 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Thu, 18 May 2017 19:13:09 +0300 Subject: [PATCH 264/492] Update App.java --- .../iluwatar/dependency/injection/App.java | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java index 8723f9b4f..a27160bf1 100644 --- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java @@ -26,7 +26,6 @@ import com.google.inject.Guice; import com.google.inject.Injector; /** - * * Dependency Injection pattern deals with how objects handle their dependencies. The pattern * implements so called inversion of control principle. Inversion of control has two specific rules: * - High-level modules should not depend on low-level modules. Both should depend on abstractions. @@ -45,28 +44,27 @@ import com.google.inject.Injector; * The fourth example takes the pattern a step further. It uses Guice framework for Dependency * Injection. {@link TobaccoModule} binds a concrete implementation to abstraction. Injector is then * used to create {@link GuiceWizard} object with correct dependencies. - * */ public class App { - /** - * Program entry point - * - * @param args command line args - */ - public static void main(String[] args) { - SimpleWizard simpleWizard = new SimpleWizard(); - simpleWizard.smoke(); + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { + SimpleWizard simpleWizard = new SimpleWizard(); + simpleWizard.smoke(); - AdvancedWizard advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); - advancedWizard.smoke(); + AdvancedWizard advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); + advancedWizard.smoke(); - AdvancedSorceress advancedSorceress = new AdvancedSorceress(); - advancedSorceress.setTobacco(new SecondBreakfastTobacco()); - advancedSorceress.smoke(); + AdvancedSorceress advancedSorceress = new AdvancedSorceress(); + advancedSorceress.setTobacco(new SecondBreakfastTobacco()); + advancedSorceress.smoke(); - Injector injector = Guice.createInjector(new TobaccoModule()); - GuiceWizard guiceWizard = injector.getInstance(GuiceWizard.class); - guiceWizard.smoke(); - } + Injector injector = Guice.createInjector(new TobaccoModule()); + GuiceWizard guiceWizard = injector.getInstance(GuiceWizard.class); + guiceWizard.smoke(); + } } From c746004f730c76ace78ff51a494d3e9c37b51a72 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Thu, 18 May 2017 19:13:45 +0300 Subject: [PATCH 265/492] Update AdvancedSorceress.java --- .../injection/AdvancedSorceress.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java index 4a952e952..5652c8a87 100644 --- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java @@ -3,17 +3,17 @@ package com.iluwatar.dependency.injection; /** * The MIT License * Copyright (c) 2014-2017 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 @@ -32,14 +32,14 @@ package com.iluwatar.dependency.injection; */ public class AdvancedSorceress implements Wizard { - private Tobacco tobacco; + private Tobacco tobacco; - public void setTobacco(Tobacco tobacco) { - this.tobacco = tobacco; - } + public void setTobacco(Tobacco tobacco) { + this.tobacco = tobacco; + } - @Override - public void smoke() { - tobacco.smoke(this); - } + @Override + public void smoke() { + tobacco.smoke(this); + } } From 08901f3c26b70d08c75bc2314855fcf3c3313985 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Thu, 18 May 2017 20:23:05 +0300 Subject: [PATCH 266/492] Update AdvancedSorceress.java --- .../com/iluwatar/dependency/injection/AdvancedSorceress.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java index 5652c8a87..44b56f415 100644 --- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java @@ -28,7 +28,6 @@ package com.iluwatar.dependency.injection; * * AdvancedSorceress implements inversion of control. It depends on abstraction that can be injected * through its setter. - * */ public class AdvancedSorceress implements Wizard { From 30dcbee2cc46c0e35a71a928793be07277c7b376 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Thu, 18 May 2017 20:26:47 +0300 Subject: [PATCH 267/492] Update AdvancedSorceress.java --- .../com/iluwatar/dependency/injection/AdvancedSorceress.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java index 44b56f415..4784c5b86 100644 --- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java @@ -25,7 +25,6 @@ package com.iluwatar.dependency.injection; /** - * * AdvancedSorceress implements inversion of control. It depends on abstraction that can be injected * through its setter. */ From 17039dc5e9856ec5ed041aee3a92a1dd83cc8e7a Mon Sep 17 00:00:00 2001 From: kapinuss Date: Thu, 18 May 2017 20:27:16 +0300 Subject: [PATCH 268/492] Update AdvancedSorceressTest.java --- .../injection/AdvancedSorceressTest.java | 71 ++++++++++--------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java index a8badef78..b2a701d0b 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java @@ -26,44 +26,51 @@ import com.iluwatar.dependency.injection.utils.InMemoryAppender; import org.junit.After; import org.junit.Before; import org.junit.Test; + import static org.junit.Assert.assertEquals; +/** + * Date: 28/04/17 - 7:40 AM + * + * @author Stanislav Kapinus + */ + public class AdvancedSorceressTest { - private InMemoryAppender appender; + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Tobacco.class); + } + + @After + public void tearDown() { + appender.stop(); + } + + /** + * Test if the {@link AdvancedSorceress} smokes whatever instance of {@link Tobacco} is passed to her + * through the setter's parameter + */ + @Test + public void testSmokeEveryThing() throws Exception { + + final Tobacco[] tobaccos = { + new OldTobyTobacco(), new RivendellTobacco(), new SecondBreakfastTobacco() + }; + + for (final Tobacco tobacco : tobaccos) { + final AdvancedSorceress advancedSorceress = new AdvancedSorceress(); + advancedSorceress.setTobacco(tobacco); + advancedSorceress.smoke(); + // Verify if the sorceress is smoking the correct tobacco ... + assertEquals("AdvancedSorceress smoking " + tobacco.getClass().getSimpleName(), appender.getLastMessage()); - @Before - public void setUp() { - appender = new InMemoryAppender(Tobacco.class); } - @After - public void tearDown() { - appender.stop(); - } + // ... and nothing else is happening. + assertEquals(tobaccos.length, appender.getLogSize()); - /** - * Test if the {@link AdvancedSorceress} smokes whatever instance of {@link Tobacco} is passed to her - * through the setter's parameter - */ - - @Test - public void testSmokeEveryThing() throws Exception { - - final Tobacco[] tobaccos = { - new OldTobyTobacco(), new RivendellTobacco(), new SecondBreakfastTobacco() - }; - - for (final Tobacco tobacco : tobaccos) { - final AdvancedSorceress advancedSorceress = new AdvancedSorceress(); - advancedSorceress.setTobacco(tobacco); - advancedSorceress.smoke(); - // Verify if the sorceress is smoking the correct tobacco ... - assertEquals("AdvancedSorceress smoking " + tobacco.getClass().getSimpleName(), appender.getLastMessage()); - - } - - // ... and nothing else is happening. - assertEquals(tobaccos.length, appender.getLogSize()); - } + } } From ae1d9cf7a80037546ffed672b5fe575632873a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 21 May 2017 09:19:29 +0300 Subject: [PATCH 269/492] Add missing license headers --- .../iluwatar/databus/AbstractDataType.java | 22 +++++++++++++++++++ .../java/com/iluwatar/databus/DataType.java | 22 +++++++++++++++++++ .../java/com/iluwatar/databus/Member.java | 22 +++++++++++++++++++ .../com/iluwatar/databus/DataBusTest.java | 22 +++++++++++++++++++ .../members/MessageCollectorMemberTest.java | 22 +++++++++++++++++++ .../databus/members/StatusMemberTest.java | 22 +++++++++++++++++++ .../injection/AdvancedSorceress.java | 22 +++++++++++++++++++ 7 files changed, 154 insertions(+) diff --git a/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java b/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java index 5ba6653de..d57e4a014 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java +++ b/data-bus/src/main/java/com/iluwatar/databus/AbstractDataType.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ /* The MIT License (MIT) diff --git a/data-bus/src/main/java/com/iluwatar/databus/DataType.java b/data-bus/src/main/java/com/iluwatar/databus/DataType.java index e5729c19d..a3dd32870 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/DataType.java +++ b/data-bus/src/main/java/com/iluwatar/databus/DataType.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ /* The MIT License (MIT) diff --git a/data-bus/src/main/java/com/iluwatar/databus/Member.java b/data-bus/src/main/java/com/iluwatar/databus/Member.java index d5ecb0152..c2ab7de32 100644 --- a/data-bus/src/main/java/com/iluwatar/databus/Member.java +++ b/data-bus/src/main/java/com/iluwatar/databus/Member.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ /* The MIT License (MIT) diff --git a/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java b/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java index 90c326ebf..f986e1681 100644 --- a/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java +++ b/data-bus/src/test/java/com/iluwatar/databus/DataBusTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.databus; import org.junit.Before; diff --git a/data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java b/data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java index 96fc090ee..35deeb5fb 100644 --- a/data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java +++ b/data-bus/src/test/java/com/iluwatar/databus/members/MessageCollectorMemberTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.databus.members; import com.iluwatar.databus.data.MessageData; diff --git a/data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java b/data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java index e5983dcea..d5afbd132 100644 --- a/data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java +++ b/data-bus/src/test/java/com/iluwatar/databus/members/StatusMemberTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.databus.members; import com.iluwatar.databus.DataBus; diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java index 4784c5b86..52256fd81 100644 --- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java +++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedSorceress.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.dependency.injection; /** From f2e35ec03df777b56f4af5f16c657211f0cfae4d Mon Sep 17 00:00:00 2001 From: Aleksandar Dudukovic Date: Tue, 23 May 2017 01:38:02 +0200 Subject: [PATCH 270/492] #567 fix version and javadoc --- marker/README.md | 10 +++++----- marker/pom.xml | 10 +--------- marker/src/main/java/App.java | 6 +++++- marker/src/main/java/Guard.java | 13 +++++++++---- marker/src/main/java/Permission.java | 1 - marker/src/main/java/Thief.java | 12 +++++++++--- marker/src/test/java/AppTest.java | 4 ---- marker/src/test/java/GuardTest.java | 4 ++-- marker/src/test/java/ThiefTest.java | 6 +++--- 9 files changed, 34 insertions(+), 32 deletions(-) diff --git a/marker/README.md b/marker/README.md index 8ff25100a..5bcdf9664 100644 --- a/marker/README.md +++ b/marker/README.md @@ -10,20 +10,20 @@ tags: --- ## Intent -Using empy interfaces as markers to distinguish special treated objects. +Using empty interfaces as markers to distinguish special treated objects. ![alt text](./etc/MarkerDiagram.png "Marker Interface") ## Applicability Use the Marker Interface pattern when -* you want to identify the special objects from normal objects -* define a type that is implemented by instances of the marked class, marker annotations can not do that +* you want to identify the special objects from normal objects (to treat them differently) +* you want to mark that some object is available for certain sort of operations ## Real world examples -* [javase.7.docs.api.java.io.Serializable](https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html) -* [javase.7.docs.api.java.lang.Cloneable](https://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html) +* [javase.8.docs.api.java.io.Serializable](https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html) +* [javase.8.docs.api.java.lang.Cloneable](https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html) ## Credits diff --git a/marker/pom.xml b/marker/pom.xml index ab92bdbc6..2842bd739 100644 --- a/marker/pom.xml +++ b/marker/pom.xml @@ -30,18 +30,10 @@ marker - - org.junit.jupiter - junit-jupiter-api - RELEASE - - - junit - junit - junit junit + test diff --git a/marker/src/main/java/App.java b/marker/src/main/java/App.java index 10ec017df..7abdda8c4 100644 --- a/marker/src/main/java/App.java +++ b/marker/src/main/java/App.java @@ -1,3 +1,6 @@ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Created by Alexis on 28-Apr-17. * With Marker interface idea is to make empty interface and extend it. @@ -25,13 +28,14 @@ public class App { */ public static void main(String[] args) { + final Logger logger = LoggerFactory.getLogger(App.class); Guard guard = new Guard(); Thief thief = new Thief(); if (guard instanceof Permission) { guard.enter(); } else { - System.out.println("You have no permission to enter, please leave this area"); + logger.info("You have no permission to enter, please leave this area"); } if (thief instanceof Permission) { diff --git a/marker/src/main/java/Guard.java b/marker/src/main/java/Guard.java index 93db6b4d7..14016f0b1 100644 --- a/marker/src/main/java/Guard.java +++ b/marker/src/main/java/Guard.java @@ -1,10 +1,15 @@ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * Created by Alexis on 29-Apr-17. + * Class defining Guard */ public class Guard implements Permission { - protected static void enter() { - System.out.println("You can enter"); - } + private static final Logger LOGGER = LoggerFactory.getLogger(Guard.class); + protected static void enter() { + + LOGGER.info("You can enter"); + } } diff --git a/marker/src/main/java/Permission.java b/marker/src/main/java/Permission.java index a422e955c..c6e78c49d 100644 --- a/marker/src/main/java/Permission.java +++ b/marker/src/main/java/Permission.java @@ -1,5 +1,4 @@ /** - * Created by Alexis on 29-Apr-17. * Interface without any methods * Marker interface is based on that assumption */ diff --git a/marker/src/main/java/Thief.java b/marker/src/main/java/Thief.java index 33eac5aca..9105057e3 100644 --- a/marker/src/main/java/Thief.java +++ b/marker/src/main/java/Thief.java @@ -1,12 +1,18 @@ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * Created by Alexis on 02-May-17. + * Class defining Thief */ public class Thief { + + private static final Logger LOGGER = LoggerFactory.getLogger(Thief.class); + protected static void steal() { - System.out.println("Steal valuable items"); + LOGGER.info("Steal valuable items"); } protected static void doNothing() { - System.out.println("Pretend nothing happened and just leave"); + LOGGER.info("Pretend nothing happened and just leave"); } } diff --git a/marker/src/test/java/AppTest.java b/marker/src/test/java/AppTest.java index 615a3c910..55fb2a17f 100644 --- a/marker/src/test/java/AppTest.java +++ b/marker/src/test/java/AppTest.java @@ -1,7 +1,3 @@ -/** - * Created by Alexis on 01-May-17. - */ - import org.junit.Test; /** diff --git a/marker/src/test/java/GuardTest.java b/marker/src/test/java/GuardTest.java index 459447367..8b33b6e7f 100644 --- a/marker/src/test/java/GuardTest.java +++ b/marker/src/test/java/GuardTest.java @@ -4,7 +4,7 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.assertThat; /** - * Created by Alexis on 02-May-17. + * Guard test */ public class GuardTest { @@ -13,4 +13,4 @@ public class GuardTest { Guard guard = new Guard(); assertThat(guard, instanceOf(Permission.class)); } -} +} \ No newline at end of file diff --git a/marker/src/test/java/ThiefTest.java b/marker/src/test/java/ThiefTest.java index bcc862803..71fe82b68 100644 --- a/marker/src/test/java/ThiefTest.java +++ b/marker/src/test/java/ThiefTest.java @@ -3,12 +3,12 @@ import org.junit.Test; import static org.junit.Assert.assertFalse; /** - * Created by Alexis on 02-May-17. + * Thief test */ public class ThiefTest { @Test - public void testGuard() { + public void testThief() { Thief thief = new Thief(); assertFalse(thief instanceof Permission); } -} +} \ No newline at end of file From 24f258848c67500d347f9cce051f27aecda48f97 Mon Sep 17 00:00:00 2001 From: shaiktaj Date: Thu, 25 May 2017 11:04:30 -0500 Subject: [PATCH 271/492] Updated ThreadSafeLazyLoadedivoryTower Added null check in private constructor to prevent instantiating by Reflection call --- .../iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java index 0b1b51b23..68f190d46 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java @@ -33,7 +33,12 @@ public final class ThreadSafeLazyLoadedIvoryTower { private static ThreadSafeLazyLoadedIvoryTower instance; - private ThreadSafeLazyLoadedIvoryTower() {} + private ThreadSafeLazyLoadedIvoryTower() { + // to prevent instantiating by Reflection call + if (instance != null) { + throw new IllegalStateException("Already initialized."); + } + } /** * The instance gets created only when it is called for first time. Lazy-loading From f87249e03b8b72cc48e7f6d04fb681a6ab9dad5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Mon, 29 May 2017 21:53:05 +0300 Subject: [PATCH 272/492] Add missing license headers --- marker/etc/marker.urm.puml | 2 ++ marker/src/main/java/App.java | 22 ++++++++++++++++++++++ marker/src/main/java/Guard.java | 22 ++++++++++++++++++++++ marker/src/main/java/Permission.java | 22 ++++++++++++++++++++++ marker/src/main/java/Thief.java | 22 ++++++++++++++++++++++ marker/src/test/java/AppTest.java | 22 ++++++++++++++++++++++ marker/src/test/java/GuardTest.java | 22 ++++++++++++++++++++++ marker/src/test/java/ThiefTest.java | 22 ++++++++++++++++++++++ 8 files changed, 156 insertions(+) create mode 100644 marker/etc/marker.urm.puml diff --git a/marker/etc/marker.urm.puml b/marker/etc/marker.urm.puml new file mode 100644 index 000000000..02af47ddf --- /dev/null +++ b/marker/etc/marker.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/marker/src/main/java/App.java b/marker/src/main/java/App.java index 7abdda8c4..d8fd54ecb 100644 --- a/marker/src/main/java/App.java +++ b/marker/src/main/java/App.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/marker/src/main/java/Guard.java b/marker/src/main/java/Guard.java index 14016f0b1..4dd2a4887 100644 --- a/marker/src/main/java/Guard.java +++ b/marker/src/main/java/Guard.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/marker/src/main/java/Permission.java b/marker/src/main/java/Permission.java index c6e78c49d..2a85b3363 100644 --- a/marker/src/main/java/Permission.java +++ b/marker/src/main/java/Permission.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ /** * Interface without any methods * Marker interface is based on that assumption diff --git a/marker/src/main/java/Thief.java b/marker/src/main/java/Thief.java index 9105057e3..b8d6464e5 100644 --- a/marker/src/main/java/Thief.java +++ b/marker/src/main/java/Thief.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/marker/src/test/java/AppTest.java b/marker/src/test/java/AppTest.java index 55fb2a17f..85fb61b16 100644 --- a/marker/src/test/java/AppTest.java +++ b/marker/src/test/java/AppTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import org.junit.Test; /** diff --git a/marker/src/test/java/GuardTest.java b/marker/src/test/java/GuardTest.java index 8b33b6e7f..eb3a4b757 100644 --- a/marker/src/test/java/GuardTest.java +++ b/marker/src/test/java/GuardTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import org.junit.Test; import static org.hamcrest.CoreMatchers.instanceOf; diff --git a/marker/src/test/java/ThiefTest.java b/marker/src/test/java/ThiefTest.java index 71fe82b68..f950809cc 100644 --- a/marker/src/test/java/ThiefTest.java +++ b/marker/src/test/java/ThiefTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import org.junit.Test; import static org.junit.Assert.assertFalse; From 0182b840af5aadfe8589d9ac496b0459335ececa Mon Sep 17 00:00:00 2001 From: Chang Liu Date: Tue, 30 May 2017 13:22:52 +0200 Subject: [PATCH 273/492] add RxJava to Real world examples of observer --- observer/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/observer/README.md b/observer/README.md index 2ac98c401..3b3fcd2c5 100644 --- a/observer/README.md +++ b/observer/README.md @@ -38,6 +38,7 @@ Use the Observer pattern in any of the following situations * [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html) * [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html) * [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html) +* [RxJava](https://github.com/ReactiveX/RxJava) ## Credits From 22a7c15accaa18b9c077a0ab756ab773dfb70629 Mon Sep 17 00:00:00 2001 From: SrdjanPaunovic Date: Fri, 2 Jun 2017 21:42:59 +0200 Subject: [PATCH 274/492] Reset execute-around/pom.xml from master --- execute-around/pom.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 59f9b3dea..765b52846 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -23,9 +23,7 @@ THE SOFTWARE. --> - 4.0.0 From 85acb1cf6c016238235f6890866123a5c6c4f42d Mon Sep 17 00:00:00 2001 From: SrdjanPaunovic Date: Sun, 4 Jun 2017 20:49:15 +0200 Subject: [PATCH 275/492] Replase system.println with logger --- extension-objects/etc/extension_obj1.png | Bin 14390 -> 0 bytes extension-objects/src/main/java/App.java | 23 +++++++++--------- .../java/concreteextensions/Commander.java | 6 ++++- .../java/concreteextensions/Sergeant.java | 6 ++++- .../main/java/concreteextensions/Soldier.java | 6 ++++- 5 files changed, 27 insertions(+), 14 deletions(-) delete mode 100644 extension-objects/etc/extension_obj1.png diff --git a/extension-objects/etc/extension_obj1.png b/extension-objects/etc/extension_obj1.png deleted file mode 100644 index e3115661f4aa51559d553c7ca27ad9da97300336..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14390 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 Z<{Bk;ux2a Date: Sun, 4 Jun 2017 21:09:17 +0200 Subject: [PATCH 276/492] Create meaningful JavaDocs instead of author names --- extension-objects/src/main/java/App.java | 3 ++- .../src/main/java/abstractextensions/CommanderExtension.java | 2 +- .../src/main/java/abstractextensions/SergeantExtension.java | 2 +- .../src/main/java/abstractextensions/SoldierExtension.java | 2 +- .../src/main/java/abstractextensions/UnitExtension.java | 2 +- .../src/main/java/concreteextensions/Commander.java | 2 +- .../src/main/java/concreteextensions/Sergeant.java | 2 +- .../src/main/java/concreteextensions/Soldier.java | 2 +- extension-objects/src/main/java/units/CommanderUnit.java | 2 +- extension-objects/src/main/java/units/SergeantUnit.java | 2 +- extension-objects/src/main/java/units/SoldierUnit.java | 2 +- extension-objects/src/main/java/units/Unit.java | 2 +- 12 files changed, 13 insertions(+), 12 deletions(-) diff --git a/extension-objects/src/main/java/App.java b/extension-objects/src/main/java/App.java index 6163f0ca2..91ee129ee 100644 --- a/extension-objects/src/main/java/App.java +++ b/extension-objects/src/main/java/App.java @@ -9,7 +9,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Created by Srdjan on 26-Apr-17. + * Anticipate that an object’s interface needs to be extended in the future. + * Additional interfaces are defined by extension objects. */ public class App { diff --git a/extension-objects/src/main/java/abstractextensions/CommanderExtension.java b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java index 3088c9f86..7f8b3ef25 100644 --- a/extension-objects/src/main/java/abstractextensions/CommanderExtension.java +++ b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java @@ -1,7 +1,7 @@ package abstractextensions; /** - * Created by Srdjan on 27-Apr-17. + * Interface with their method */ public interface CommanderExtension extends UnitExtension { diff --git a/extension-objects/src/main/java/abstractextensions/SergeantExtension.java b/extension-objects/src/main/java/abstractextensions/SergeantExtension.java index dc7bbdc70..953d15fc0 100644 --- a/extension-objects/src/main/java/abstractextensions/SergeantExtension.java +++ b/extension-objects/src/main/java/abstractextensions/SergeantExtension.java @@ -1,7 +1,7 @@ package abstractextensions; /** - * Created by Srdjan on 27-Apr-17. + * Interface with their method */ public interface SergeantExtension extends UnitExtension { diff --git a/extension-objects/src/main/java/abstractextensions/SoldierExtension.java b/extension-objects/src/main/java/abstractextensions/SoldierExtension.java index 1715811f8..9d995bc0e 100644 --- a/extension-objects/src/main/java/abstractextensions/SoldierExtension.java +++ b/extension-objects/src/main/java/abstractextensions/SoldierExtension.java @@ -1,7 +1,7 @@ package abstractextensions; /** - * Created by Srdjan on 26-Apr-17. + * Interface with their method */ public interface SoldierExtension extends UnitExtension { void soldierReady(); diff --git a/extension-objects/src/main/java/abstractextensions/UnitExtension.java b/extension-objects/src/main/java/abstractextensions/UnitExtension.java index 03c58d181..073f49a48 100644 --- a/extension-objects/src/main/java/abstractextensions/UnitExtension.java +++ b/extension-objects/src/main/java/abstractextensions/UnitExtension.java @@ -1,7 +1,7 @@ package abstractextensions; /** - * Created by Srdjan on 26-Apr-17. + * Other Extensions will extend this interface */ public interface UnitExtension { } diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java index 89720000a..a18f5412e 100644 --- a/extension-objects/src/main/java/concreteextensions/Commander.java +++ b/extension-objects/src/main/java/concreteextensions/Commander.java @@ -6,7 +6,7 @@ import org.slf4j.LoggerFactory; import units.CommanderUnit; /** - * Created by Srdjan on 27-Apr-17. + * Class defining Commander */ public class Commander implements CommanderExtension { diff --git a/extension-objects/src/main/java/concreteextensions/Sergeant.java b/extension-objects/src/main/java/concreteextensions/Sergeant.java index 13b641089..0f92a2170 100644 --- a/extension-objects/src/main/java/concreteextensions/Sergeant.java +++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java @@ -6,7 +6,7 @@ import org.slf4j.LoggerFactory; import units.SergeantUnit; /** - * Created by Srdjan on 27-Apr-17. + * Class defining Sergeant */ public class Sergeant implements SergeantExtension { diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java index 630fa1a97..790e78fb2 100644 --- a/extension-objects/src/main/java/concreteextensions/Soldier.java +++ b/extension-objects/src/main/java/concreteextensions/Soldier.java @@ -6,7 +6,7 @@ import org.slf4j.LoggerFactory; import units.SoldierUnit; /** - * Created by Srdjan on 26-Apr-17. + * Class defining Soldier */ public class Soldier implements SoldierExtension { diff --git a/extension-objects/src/main/java/units/CommanderUnit.java b/extension-objects/src/main/java/units/CommanderUnit.java index a5ed60a76..06ad6e127 100644 --- a/extension-objects/src/main/java/units/CommanderUnit.java +++ b/extension-objects/src/main/java/units/CommanderUnit.java @@ -4,7 +4,7 @@ import abstractextensions.UnitExtension; import concreteextensions.Commander; /** - * Created by Srdjan on 27-Apr-17. + * Class defining CommanderUnit */ public class CommanderUnit extends Unit { diff --git a/extension-objects/src/main/java/units/SergeantUnit.java b/extension-objects/src/main/java/units/SergeantUnit.java index 876a50db5..a84631b12 100644 --- a/extension-objects/src/main/java/units/SergeantUnit.java +++ b/extension-objects/src/main/java/units/SergeantUnit.java @@ -4,7 +4,7 @@ import abstractextensions.UnitExtension; import concreteextensions.Sergeant; /** - * Created by Srdjan on 27-Apr-17. + * Class defining SergeantUnit */ public class SergeantUnit extends Unit { diff --git a/extension-objects/src/main/java/units/SoldierUnit.java b/extension-objects/src/main/java/units/SoldierUnit.java index 9e566796b..957f68b86 100644 --- a/extension-objects/src/main/java/units/SoldierUnit.java +++ b/extension-objects/src/main/java/units/SoldierUnit.java @@ -4,7 +4,7 @@ import abstractextensions.UnitExtension; import concreteextensions.Soldier; /** - * Created by Srdjan on 26-Apr-17. + * Class defining SoldierUnit */ public class SoldierUnit extends Unit { diff --git a/extension-objects/src/main/java/units/Unit.java b/extension-objects/src/main/java/units/Unit.java index d6901ec75..411a3e3ff 100644 --- a/extension-objects/src/main/java/units/Unit.java +++ b/extension-objects/src/main/java/units/Unit.java @@ -3,7 +3,7 @@ package units; import abstractextensions.UnitExtension; /** - * Created by Srdjan on 26-Apr-17. + * Class defining Unit, other units will extend this class */ public class Unit { From a0916aab6c055d38ec2622cfd5fcf7d87fc8966b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sr=C4=91an=20Paunovi=C4=87?= Date: Sun, 4 Jun 2017 21:12:30 +0200 Subject: [PATCH 277/492] Update README.md --- extension-objects/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension-objects/README.md b/extension-objects/README.md index e345952ed..9b5c93a22 100644 --- a/extension-objects/README.md +++ b/extension-objects/README.md @@ -13,7 +13,7 @@ tags: Anticipate that an object’s interface needs to be extended in the future. Additional interfaces are defined by extension objects. -![alt text](./etc/extension_obj1.png "Extension objects") +![Extension_objects](./etc/extension_obj.png "Extension objects") ## Applicability Use the Extension Objects pattern when: From 41d487d32af294f32657e0a014e56c23723b15ff Mon Sep 17 00:00:00 2001 From: prafful1 Date: Wed, 7 Jun 2017 20:22:15 +0530 Subject: [PATCH 278/492] Few additions in readme Adding Consequences and General usage of Adapter Pattern section to the Readme doc. --- adapter/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/adapter/README.md b/adapter/README.md index 6bd6d66e1..4059ea852 100644 --- a/adapter/README.md +++ b/adapter/README.md @@ -21,6 +21,9 @@ incompatible interfaces. ![alt text](./etc/adapter.png "Adapter") +## General usage of Adapter Pattern: ++ Wrappers used to adopt 3rd parties libraries and frameworks - most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code. + ## Applicability Use the Adapter pattern when @@ -28,6 +31,19 @@ Use the Adapter pattern when * you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces * you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class. +## Consequences: +Class and object adapters have different trade-offs. A class adapter + +* adapts Adaptee to Target by committing to a concrete Adaptee class. As a consequence, a class adapter won’t work when we want to adapt a class and all its subclasses. +* let’s Adapter override some of Adaptee’s behavior, since Adapter is a subclass of Adaptee. +* introduces only one object, and no additional pointer indirection is needed to get to the adaptee. + +An object adapter + +* let’s a single Adapter work with many Adaptees—that is, the Adaptee itself and all of its subclasses (if any). The Adapter can also add functionality to all Adaptees at once. +* makes it harder to override Adaptee behavior. It will require subclassing Adaptee and making Adapter refer to the subclass rather than the Adaptee itself. + + ## Real world examples * [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) From 73934e25e5bfbca572d8b3f275763f8e684d8c60 Mon Sep 17 00:00:00 2001 From: Harshrajsinh Thakor Date: Fri, 9 Jun 2017 17:17:56 -0700 Subject: [PATCH 279/492] Refactored the Functional Interface to the Specialized Functional Interface. --- .../test/java/com/iluwatar/interpreter/ExpressionTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java index 2d444373c..2241b882b 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java @@ -28,6 +28,8 @@ import static org.junit.Assert.assertNotNull; import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; +import java.util.function.IntBinaryOperator; + import org.junit.Test; /** @@ -45,14 +47,14 @@ public abstract class ExpressionTest { * @param resultCalc The function used to calculate the expected result * @return A data set with test entries */ - static List prepareParameters(final BiFunction resultCalc) { + static List prepareParameters(final IntBinaryOperator resultCalc) { final List testData = new ArrayList<>(); for (int i = -10; i < 10; i++) { for (int j = -10; j < 10; j++) { testData.add(new Object[]{ new NumberExpression(i), new NumberExpression(j), - resultCalc.apply(i, j) + resultCalc.applyAsInt(i, j) }); } } From 3d29755842e9dee61b28845b039652bcb7350642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 11 Jun 2017 19:37:52 +0300 Subject: [PATCH 280/492] Add license headers --- .../etc/extension-objects.urm.puml | 2 ++ extension-objects/pom.xml | 24 +++++++++++++++++++ extension-objects/src/main/java/App.java | 22 +++++++++++++++++ .../CommanderExtension.java | 22 +++++++++++++++++ .../abstractextensions/SergeantExtension.java | 22 +++++++++++++++++ .../abstractextensions/SoldierExtension.java | 22 +++++++++++++++++ .../abstractextensions/UnitExtension.java | 22 +++++++++++++++++ .../java/concreteextensions/Commander.java | 22 +++++++++++++++++ .../java/concreteextensions/Sergeant.java | 22 +++++++++++++++++ .../main/java/concreteextensions/Soldier.java | 22 +++++++++++++++++ .../src/main/java/units/CommanderUnit.java | 22 +++++++++++++++++ .../src/main/java/units/SergeantUnit.java | 22 +++++++++++++++++ .../src/main/java/units/SoldierUnit.java | 22 +++++++++++++++++ .../src/main/java/units/Unit.java | 22 +++++++++++++++++ extension-objects/src/test/java/AppTest.java | 22 +++++++++++++++++ .../concreteextensions/CommanderTest.java | 22 +++++++++++++++++ .../java/concreteextensions/SergeantTest.java | 22 +++++++++++++++++ .../java/concreteextensions/SoldierTest.java | 22 +++++++++++++++++ .../test/java/units/CommanderUnitTest.java | 22 +++++++++++++++++ .../src/test/java/units/SergeantUnitTest.java | 22 +++++++++++++++++ .../src/test/java/units/SoldierUnitTest.java | 22 +++++++++++++++++ .../src/test/java/units/UnitTest.java | 22 +++++++++++++++++ 22 files changed, 466 insertions(+) create mode 100644 extension-objects/etc/extension-objects.urm.puml diff --git a/extension-objects/etc/extension-objects.urm.puml b/extension-objects/etc/extension-objects.urm.puml new file mode 100644 index 000000000..02af47ddf --- /dev/null +++ b/extension-objects/etc/extension-objects.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/extension-objects/pom.xml b/extension-objects/pom.xml index 4c0b0a230..ad05e4a67 100644 --- a/extension-objects/pom.xml +++ b/extension-objects/pom.xml @@ -1,4 +1,28 @@ + diff --git a/extension-objects/src/main/java/App.java b/extension-objects/src/main/java/App.java index 91ee129ee..0fcc548dc 100644 --- a/extension-objects/src/main/java/App.java +++ b/extension-objects/src/main/java/App.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import abstractextensions.CommanderExtension; import abstractextensions.SergeantExtension; import abstractextensions.SoldierExtension; diff --git a/extension-objects/src/main/java/abstractextensions/CommanderExtension.java b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java index 7f8b3ef25..66dd3a25e 100644 --- a/extension-objects/src/main/java/abstractextensions/CommanderExtension.java +++ b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 abstractextensions; /** diff --git a/extension-objects/src/main/java/abstractextensions/SergeantExtension.java b/extension-objects/src/main/java/abstractextensions/SergeantExtension.java index 953d15fc0..8df30c63e 100644 --- a/extension-objects/src/main/java/abstractextensions/SergeantExtension.java +++ b/extension-objects/src/main/java/abstractextensions/SergeantExtension.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 abstractextensions; /** diff --git a/extension-objects/src/main/java/abstractextensions/SoldierExtension.java b/extension-objects/src/main/java/abstractextensions/SoldierExtension.java index 9d995bc0e..9296b6204 100644 --- a/extension-objects/src/main/java/abstractextensions/SoldierExtension.java +++ b/extension-objects/src/main/java/abstractextensions/SoldierExtension.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 abstractextensions; /** diff --git a/extension-objects/src/main/java/abstractextensions/UnitExtension.java b/extension-objects/src/main/java/abstractextensions/UnitExtension.java index 073f49a48..b3b3bf7fa 100644 --- a/extension-objects/src/main/java/abstractextensions/UnitExtension.java +++ b/extension-objects/src/main/java/abstractextensions/UnitExtension.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 abstractextensions; /** diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java index a18f5412e..8094d2887 100644 --- a/extension-objects/src/main/java/concreteextensions/Commander.java +++ b/extension-objects/src/main/java/concreteextensions/Commander.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 concreteextensions; import abstractextensions.CommanderExtension; diff --git a/extension-objects/src/main/java/concreteextensions/Sergeant.java b/extension-objects/src/main/java/concreteextensions/Sergeant.java index 0f92a2170..892a3d372 100644 --- a/extension-objects/src/main/java/concreteextensions/Sergeant.java +++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 concreteextensions; import abstractextensions.SergeantExtension; diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java index 790e78fb2..79db74d6c 100644 --- a/extension-objects/src/main/java/concreteextensions/Soldier.java +++ b/extension-objects/src/main/java/concreteextensions/Soldier.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 concreteextensions; import abstractextensions.SoldierExtension; diff --git a/extension-objects/src/main/java/units/CommanderUnit.java b/extension-objects/src/main/java/units/CommanderUnit.java index 06ad6e127..61b7a050d 100644 --- a/extension-objects/src/main/java/units/CommanderUnit.java +++ b/extension-objects/src/main/java/units/CommanderUnit.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import abstractextensions.UnitExtension; diff --git a/extension-objects/src/main/java/units/SergeantUnit.java b/extension-objects/src/main/java/units/SergeantUnit.java index a84631b12..a655abac4 100644 --- a/extension-objects/src/main/java/units/SergeantUnit.java +++ b/extension-objects/src/main/java/units/SergeantUnit.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import abstractextensions.UnitExtension; diff --git a/extension-objects/src/main/java/units/SoldierUnit.java b/extension-objects/src/main/java/units/SoldierUnit.java index 957f68b86..03617dd27 100644 --- a/extension-objects/src/main/java/units/SoldierUnit.java +++ b/extension-objects/src/main/java/units/SoldierUnit.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import abstractextensions.UnitExtension; diff --git a/extension-objects/src/main/java/units/Unit.java b/extension-objects/src/main/java/units/Unit.java index 411a3e3ff..1bf251a8e 100644 --- a/extension-objects/src/main/java/units/Unit.java +++ b/extension-objects/src/main/java/units/Unit.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import abstractextensions.UnitExtension; diff --git a/extension-objects/src/test/java/AppTest.java b/extension-objects/src/test/java/AppTest.java index 287ffc131..485788112 100644 --- a/extension-objects/src/test/java/AppTest.java +++ b/extension-objects/src/test/java/AppTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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. + */ import org.junit.Test; /** diff --git a/extension-objects/src/test/java/concreteextensions/CommanderTest.java b/extension-objects/src/test/java/concreteextensions/CommanderTest.java index 82079c69a..11f0cc60e 100644 --- a/extension-objects/src/test/java/concreteextensions/CommanderTest.java +++ b/extension-objects/src/test/java/concreteextensions/CommanderTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 concreteextensions; import org.junit.Test; diff --git a/extension-objects/src/test/java/concreteextensions/SergeantTest.java b/extension-objects/src/test/java/concreteextensions/SergeantTest.java index 7b29057f6..2deddca90 100644 --- a/extension-objects/src/test/java/concreteextensions/SergeantTest.java +++ b/extension-objects/src/test/java/concreteextensions/SergeantTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 concreteextensions; import org.junit.Test; diff --git a/extension-objects/src/test/java/concreteextensions/SoldierTest.java b/extension-objects/src/test/java/concreteextensions/SoldierTest.java index 02a3144c2..affc6ee8b 100644 --- a/extension-objects/src/test/java/concreteextensions/SoldierTest.java +++ b/extension-objects/src/test/java/concreteextensions/SoldierTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 concreteextensions; import org.junit.Test; diff --git a/extension-objects/src/test/java/units/CommanderUnitTest.java b/extension-objects/src/test/java/units/CommanderUnitTest.java index 75bf5f4fc..8f4c1ca8d 100644 --- a/extension-objects/src/test/java/units/CommanderUnitTest.java +++ b/extension-objects/src/test/java/units/CommanderUnitTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import abstractextensions.CommanderExtension; diff --git a/extension-objects/src/test/java/units/SergeantUnitTest.java b/extension-objects/src/test/java/units/SergeantUnitTest.java index af2eca7cc..de773b59e 100644 --- a/extension-objects/src/test/java/units/SergeantUnitTest.java +++ b/extension-objects/src/test/java/units/SergeantUnitTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import abstractextensions.SergeantExtension; diff --git a/extension-objects/src/test/java/units/SoldierUnitTest.java b/extension-objects/src/test/java/units/SoldierUnitTest.java index 19b0c2923..06a1f7611 100644 --- a/extension-objects/src/test/java/units/SoldierUnitTest.java +++ b/extension-objects/src/test/java/units/SoldierUnitTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import abstractextensions.SoldierExtension; diff --git a/extension-objects/src/test/java/units/UnitTest.java b/extension-objects/src/test/java/units/UnitTest.java index 773b485ce..a7d530032 100644 --- a/extension-objects/src/test/java/units/UnitTest.java +++ b/extension-objects/src/test/java/units/UnitTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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 units; import org.junit.Test; From edea7d22205f5dc76b733531d29150a2f864b721 Mon Sep 17 00:00:00 2001 From: Harshrajsinh Thakor Date: Wed, 14 Jun 2017 11:58:05 -0700 Subject: [PATCH 281/492] Refactored Function to IntFunction. --- .../src/test/java/com/iluwatar/threadpool/TaskTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java index b3f253056..4a2a06de8 100644 --- a/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java +++ b/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java @@ -34,6 +34,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.function.ToIntFunction; import java.util.stream.Collectors; import org.junit.Test; @@ -58,7 +60,7 @@ public abstract class TaskTest { /** * The task factory, used to create new test items */ - private final Function factory; + private final IntFunction factory; /** * The expected time needed to run the task 1 single time, in milli seconds @@ -71,7 +73,7 @@ public abstract class TaskTest { * @param factory The task factory, used to create new test items * @param expectedExecutionTime The expected time needed to run the task 1 time, in milli seconds */ - public TaskTest(final Function factory, final int expectedExecutionTime) { + public TaskTest(final IntFunction factory, final int expectedExecutionTime) { this.factory = factory; this.expectedExecutionTime = expectedExecutionTime; } From d793160bce695af33e8d0c55b9ffcb3e0f2d6f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 30 Jun 2017 20:31:31 +0300 Subject: [PATCH 282/492] Reach milestone 1.16.0 --- abstract-document/pom.xml | 2 +- abstract-factory/pom.xml | 2 +- adapter/pom.xml | 2 +- aggregator-microservices/aggregator-service/pom.xml | 2 +- aggregator-microservices/information-microservice/pom.xml | 2 +- aggregator-microservices/inventory-microservice/pom.xml | 2 +- aggregator-microservices/pom.xml | 2 +- api-gateway/api-gateway-service/pom.xml | 2 +- api-gateway/image-microservice/pom.xml | 2 +- api-gateway/pom.xml | 2 +- api-gateway/price-microservice/pom.xml | 2 +- async-method-invocation/pom.xml | 2 +- balking/pom.xml | 2 +- bridge/pom.xml | 2 +- builder/pom.xml | 2 +- business-delegate/pom.xml | 2 +- caching/pom.xml | 2 +- callback/pom.xml | 2 +- chain/pom.xml | 2 +- command/pom.xml | 2 +- composite/pom.xml | 2 +- converter/pom.xml | 2 +- dao/pom.xml | 2 +- data-bus/pom.xml | 2 +- data-mapper/pom.xml | 2 +- decorator/pom.xml | 2 +- delegation/pom.xml | 2 +- dependency-injection/pom.xml | 2 +- double-checked-locking/pom.xml | 2 +- double-dispatch/pom.xml | 2 +- event-aggregator/pom.xml | 2 +- event-asynchronous/pom.xml | 2 +- event-driven-architecture/pom.xml | 2 +- event-queue/pom.xml | 4 ++-- execute-around/pom.xml | 2 +- extension-objects/pom.xml | 2 +- facade/pom.xml | 2 +- factory-kit/pom.xml | 2 +- factory-method/pom.xml | 2 +- feature-toggle/pom.xml | 2 +- fluentinterface/pom.xml | 2 +- flux/pom.xml | 2 +- flyweight/pom.xml | 2 +- front-controller/pom.xml | 2 +- guarded-suspension/pom.xml | 2 +- half-sync-half-async/pom.xml | 2 +- hexagonal/pom.xml | 2 +- intercepting-filter/pom.xml | 2 +- interpreter/pom.xml | 2 +- iterator/pom.xml | 2 +- layers/pom.xml | 2 +- lazy-loading/pom.xml | 2 +- marker/pom.xml | 2 +- mediator/pom.xml | 2 +- memento/pom.xml | 2 +- message-channel/pom.xml | 2 +- model-view-controller/pom.xml | 2 +- model-view-presenter/pom.xml | 2 +- module/pom.xml | 2 +- monad/pom.xml | 2 +- monostate/pom.xml | 2 +- multiton/pom.xml | 2 +- mute-idiom/pom.xml | 2 +- mutex/pom.xml | 2 +- naked-objects/dom/pom.xml | 2 +- naked-objects/fixture/pom.xml | 2 +- naked-objects/integtests/pom.xml | 2 +- naked-objects/pom.xml | 8 ++++---- naked-objects/webapp/pom.xml | 2 +- null-object/pom.xml | 2 +- object-mother/pom.xml | 2 +- object-pool/pom.xml | 2 +- observer/pom.xml | 2 +- page-object/pom.xml | 2 +- poison-pill/pom.xml | 2 +- pom.xml | 2 +- private-class-data/pom.xml | 2 +- producer-consumer/pom.xml | 2 +- promise/pom.xml | 2 +- property/pom.xml | 2 +- prototype/pom.xml | 2 +- proxy/pom.xml | 2 +- publish-subscribe/pom.xml | 2 +- queue-load-leveling/pom.xml | 2 +- reactor/pom.xml | 2 +- reader-writer-lock/pom.xml | 2 +- repository/pom.xml | 2 +- resource-acquisition-is-initialization/pom.xml | 2 +- semaphore/pom.xml | 2 +- servant/pom.xml | 2 +- service-layer/pom.xml | 2 +- service-locator/pom.xml | 2 +- singleton/pom.xml | 2 +- specification/pom.xml | 2 +- state/pom.xml | 2 +- step-builder/pom.xml | 2 +- strategy/pom.xml | 2 +- template-method/pom.xml | 2 +- thread-pool/pom.xml | 2 +- tls/pom.xml | 2 +- tolerant-reader/pom.xml | 2 +- twin/pom.xml | 2 +- value-object/pom.xml | 2 +- visitor/pom.xml | 2 +- 104 files changed, 108 insertions(+), 108 deletions(-) diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml index 54b157df6..1f42c42e7 100644 --- a/abstract-document/pom.xml +++ b/abstract-document/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 abstract-document diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index d37159409..909246430 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 abstract-factory diff --git a/adapter/pom.xml b/adapter/pom.xml index 8cf754618..c746c8ba6 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 adapter diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml index 477ce00c8..91d653984 100644 --- a/aggregator-microservices/aggregator-service/pom.xml +++ b/aggregator-microservices/aggregator-service/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml index 234daa25d..01071327e 100644 --- a/aggregator-microservices/information-microservice/pom.xml +++ b/aggregator-microservices/information-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml index bdd96eec9..413db0c7f 100644 --- a/aggregator-microservices/inventory-microservice/pom.xml +++ b/aggregator-microservices/inventory-microservice/pom.xml @@ -29,7 +29,7 @@ aggregator-microservices com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml index e08ee58f8..44c3ff8c8 100644 --- a/aggregator-microservices/pom.xml +++ b/aggregator-microservices/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 aggregator-microservices diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml index e36b09fd4..d72a6be25 100644 --- a/api-gateway/api-gateway-service/pom.xml +++ b/api-gateway/api-gateway-service/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 api-gateway-service diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml index b9430ff69..21ba9f47b 100644 --- a/api-gateway/image-microservice/pom.xml +++ b/api-gateway/image-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml index 7fdc54f8a..2ddc1612d 100644 --- a/api-gateway/pom.xml +++ b/api-gateway/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 api-gateway diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml index 68dc75640..b7d849350 100644 --- a/api-gateway/price-microservice/pom.xml +++ b/api-gateway/price-microservice/pom.xml @@ -29,7 +29,7 @@ api-gateway com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index 1dc9a6b73..5abfab610 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 async-method-invocation diff --git a/balking/pom.xml b/balking/pom.xml index 2e27d9332..905e5aa60 100644 --- a/balking/pom.xml +++ b/balking/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/bridge/pom.xml b/bridge/pom.xml index 7c60f8ef8..94e341def 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 bridge diff --git a/builder/pom.xml b/builder/pom.xml index 806d61b0a..d355f5d57 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 builder diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index 6ac3d9f4f..7cf9cc9c8 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 business-delegate diff --git a/caching/pom.xml b/caching/pom.xml index 6ec90234d..e751937aa 100644 --- a/caching/pom.xml +++ b/caching/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 caching diff --git a/callback/pom.xml b/callback/pom.xml index a64ddac51..ee6baa7b9 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 callback diff --git a/chain/pom.xml b/chain/pom.xml index 7b283b012..de0345f79 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 chain diff --git a/command/pom.xml b/command/pom.xml index cbf851701..e23ab93f0 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 command diff --git a/composite/pom.xml b/composite/pom.xml index f3b1a38b5..5ad4cca85 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 composite diff --git a/converter/pom.xml b/converter/pom.xml index 569899f1d..1dda99c2f 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -29,7 +29,7 @@ java-design-patterns com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/dao/pom.xml b/dao/pom.xml index b7de27bd4..872ec497d 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 dao diff --git a/data-bus/pom.xml b/data-bus/pom.xml index 68065f00a..4611b6981 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -33,7 +33,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 data-bus diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml index 878f02fed..9e8d94a65 100644 --- a/data-mapper/pom.xml +++ b/data-mapper/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 data-mapper diff --git a/decorator/pom.xml b/decorator/pom.xml index 5b6d24723..625a71479 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 decorator diff --git a/delegation/pom.xml b/delegation/pom.xml index befd02a59..2c47a89a7 100644 --- a/delegation/pom.xml +++ b/delegation/pom.xml @@ -30,7 +30,7 @@ java-design-patterns com.iluwatar - 1.16.0-SNAPSHOT + 1.16.0 4.0.0 diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index ccbbea9a2..72acfde9d 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index 7e19561de..3d2742d8e 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -27,7 +27,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 double-checked-locking diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index c87efc185..701218164 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index 276aecd0c..b70978bf4 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -28,7 +28,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 event-aggregator diff --git a/event-asynchronous/pom.xml b/event-asynchronous/pom.xml index a10fec55d..12df2705c 100644 --- a/event-asynchronous/pom.xml +++ b/event-asynchronous/pom.xml @@ -29,7 +29,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 event-asynchronous diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml index f021f4023..68182e2ba 100644 --- a/event-driven-architecture/pom.xml +++ b/event-driven-architecture/pom.xml @@ -31,7 +31,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.16.0 event-driven-architecture diff --git a/event-queue/pom.xml b/event-queue/pom.xml index fc857b425..209f0a36e 100644 --- a/event-queue/pom.xml +++ b/event-queue/pom.xml @@ -2,7 +2,7 @@ + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.16.0-SNAPSHOT + + cqrs + + + junit + junit + test + + + com.h2database + h2 + + + org.hibernate + hibernate-core + + + diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java new file mode 100644 index 000000000..c472e2772 --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java @@ -0,0 +1,10 @@ +package com.iluwatar.cqrs.app; + +public class App { + + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + +} diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java b/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java new file mode 100644 index 000000000..ce9181370 --- /dev/null +++ b/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java @@ -0,0 +1,14 @@ +package com.iluwatar.cqrs; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class AppTest { + + @Test + public void test() { + fail("Not yet implemented"); + } + +} From ca73621f4d2845383c8cca4917a3998ebfa5fe00 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Tue, 20 Jun 2017 21:34:49 +0000 Subject: [PATCH 285/492] create data model --- .../iluwatar/cqrs/domain/model/Author.java | 60 ++++++++++++++++++ .../com/iluwatar/cqrs/domain/model/Book.java | 62 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java new file mode 100644 index 000000000..fa2cbc43a --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java @@ -0,0 +1,60 @@ +package com.iluwatar.cqrs.domain.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +/** + * + * @author Sabiq Ihab + * + */ +@Entity +public class Author { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String username; + private String name; + private String email; + + /** + * + * @param username + * @param name + * @param email + */ + public Author(String username, String name, String email) { + super(); + this.username = username; + this.name = name; + this.email = email; + } + + public Author() { + super(); + } + + public long getId() { + return id; + } + + public String getUsername() { + return username; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + @Override + public String toString() { + return "Author [name=" + name + ", email=" + email + "]"; + } + +} diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java new file mode 100644 index 000000000..37b861d36 --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java @@ -0,0 +1,62 @@ +package com.iluwatar.cqrs.domain.model; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +/** + * + * @author Sabiq Ihab + * + */ +@Entity +public class Book { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String title; + private double price; + @ManyToOne + private Author author; + + /** + * + * @param title + * @param price + * @param author + */ + public Book(String title, double price, Author author) { + super(); + this.title = title; + this.price = price; + this.author = author; + } + + public Book() { + super(); + } + + public long getId() { + return id; + } + + public String getTitle() { + return title; + } + + public double getPrice() { + return price; + } + + public Author getAuthor() { + return author; + } + + @Override + public String toString() { + return "Book [title=" + title + ", price=" + price + ", author=" + author + "]"; + } + +} From 8208f6252b765844bf524a09ce2a826094ffe3e4 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Tue, 20 Jun 2017 21:35:45 +0000 Subject: [PATCH 286/492] add hibernate.cfg and HibernateUtil class --- .../com/iluwatar/cqrs/util/HibernateUtil.java | 36 +++++++++++++++++++ cqrs/src/main/resources/hibernate.cfg.xml | 15 ++++++++ 2 files changed, 51 insertions(+) create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java create mode 100644 cqrs/src/main/resources/hibernate.cfg.xml diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java b/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java new file mode 100644 index 000000000..9e19e05d4 --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java @@ -0,0 +1,36 @@ +package com.iluwatar.cqrs.util; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; + +/** + * + * @author Sabiq Ihab + * + */ +public class HibernateUtil { + + private static final SessionFactory SESSIONFACTORY = buildSessionFactory(); + + private static SessionFactory buildSessionFactory() { + // A SessionFactory is set up once for an application! + final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure() // configures settings // + // from hibernate.cfg.xml + .build(); + try { + return new MetadataSources(registry).buildMetadata().buildSessionFactory(); + } catch (Throwable ex) { + StandardServiceRegistryBuilder.destroy(registry); + // TODO HibernateUtil : change print with logger + System.err.println("Initial SessionFactory creation failed." + ex); + throw new ExceptionInInitializerError(ex); + } + } + + public static SessionFactory getSessionFactory() { + return SESSIONFACTORY; + } + +} diff --git a/cqrs/src/main/resources/hibernate.cfg.xml b/cqrs/src/main/resources/hibernate.cfg.xml new file mode 100644 index 000000000..a6ca21983 --- /dev/null +++ b/cqrs/src/main/resources/hibernate.cfg.xml @@ -0,0 +1,15 @@ + + + + + + org.hibernate.dialect.H2Dialect + org.h2.Driver + jdbc:h2:mem:test + sa + create + + + + \ No newline at end of file From f3902ffc1671aad1a476f2ed6353004f298189f8 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Wed, 21 Jun 2017 00:52:38 +0000 Subject: [PATCH 287/492] add setters and protected no-arg constructor --- .../com/iluwatar/cqrs/domain/model/Author.java | 18 +++++++++++++++++- .../com/iluwatar/cqrs/domain/model/Book.java | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java index fa2cbc43a..5008a233a 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java @@ -32,7 +32,7 @@ public class Author { this.email = email; } - public Author() { + protected Author() { super(); } @@ -40,18 +40,34 @@ public class Author { return id; } + public void setId(long id) { + this.id = id; + } + public String getUsername() { return username; } + public void setUsername(String username) { + this.username = username; + } + public String getName() { return name; } + public void setName(String name) { + this.name = name; + } + public String getEmail() { return email; } + public void setEmail(String email) { + this.email = email; + } + @Override public String toString() { return "Author [name=" + name + ", email=" + email + "]"; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java index 37b861d36..6c04f2bf5 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java @@ -34,7 +34,7 @@ public class Book { this.author = author; } - public Book() { + protected Book() { super(); } @@ -42,18 +42,34 @@ public class Book { return id; } + public void setId(long id) { + this.id = id; + } + public String getTitle() { return title; } + public void setTitle(String title) { + this.title = title; + } + public double getPrice() { return price; } + public void setPrice(double price) { + this.price = price; + } + public Author getAuthor() { return author; } + public void setAuthor(Author author) { + this.author = author; + } + @Override public String toString() { return "Book [title=" + title + ", price=" + price + ", author=" + author + "]"; From 15a25f0ef32544a7f12e3e01048721655cc01241 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Wed, 21 Jun 2017 00:53:20 +0000 Subject: [PATCH 288/492] add DTOs --- .../java/com/iluwatar/cqrs/dto/AuthorDTO.java | 37 +++++++++++++++++++ .../java/com/iluwatar/cqrs/dto/BookDTO.java | 26 +++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/dto/AuthorDTO.java create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/AuthorDTO.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/AuthorDTO.java new file mode 100644 index 000000000..a6ce20912 --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/AuthorDTO.java @@ -0,0 +1,37 @@ +package com.iluwatar.cqrs.dto; + +public class AuthorDTO { + + private String name; + private String email; + private String username; + + public AuthorDTO(String name, String email, String username) { + super(); + this.name = name; + this.email = email; + this.username = username; + } + + public AuthorDTO() { + super(); + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public String getUsername() { + return username; + } + + @Override + public String toString() { + return "AuthorDTO [name=" + name + ", email=" + email + ", username=" + username + "]"; + } + +} diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java new file mode 100644 index 000000000..f29aa14ca --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java @@ -0,0 +1,26 @@ +package com.iluwatar.cqrs.dto; + +public class BookDTO { + + private String title; + private double price; + + public BookDTO(String title, double price) { + super(); + this.title = title; + this.price = price; + } + + public BookDTO() { + super(); + } + + public String getTitle() { + return title; + } + + public double getPrice() { + return price; + } + +} From 51bcee5d7d710269e4bedf4589586463b2767f2f Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Wed, 21 Jun 2017 00:54:22 +0000 Subject: [PATCH 289/492] add Queries and Commands Interfaces --- .../cqrs/commandes/ICommandService.java | 19 ++++++++++++++++++ .../iluwatar/cqrs/queries/IQueryService.java | 20 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java new file mode 100644 index 000000000..4ccb0f456 --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java @@ -0,0 +1,19 @@ +package com.iluwatar.cqrs.commandes; + +public interface ICommandService { + + public abstract void authorCreated(String username, String name, String email); + + public abstract void bookAddedToAuthor(String title, double price, String username); + + public abstract void authorNameUpdated(String username, String name); + + public abstract void authorUsernameUpdated(String oldUsername, String newUsername); + + public abstract void authorEmailUpdated(String username, String email); + + public abstract void bookTitleUpdated(String oldTitle, String newTitle); + + public abstract void bookPriceUpdated(String title, double price); + +} diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java new file mode 100644 index 000000000..3cf4a2945 --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java @@ -0,0 +1,20 @@ +package com.iluwatar.cqrs.queries; + +import java.util.List; + +import com.iluwatar.cqrs.dto.AuthorDTO; +import com.iluwatar.cqrs.dto.BookDTO; + +public interface IQueryService { + + public abstract AuthorDTO getAuthorByUsername(String username); + + public abstract Double getBookPrice(String title); + + public abstract List getAuthorBooks(String username); + + public abstract long getAuthorBooksCount(String username); + + public abstract long getAuthorsCount(); + +} From 8881950e6d44f7ee2af9147709823eb7d2f4f6c0 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Wed, 21 Jun 2017 23:33:13 +0000 Subject: [PATCH 290/492] add toString() to BookDTO --- cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java index f29aa14ca..aa015d01b 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java @@ -23,4 +23,9 @@ public class BookDTO { return price; } + @Override + public String toString() { + return "BookDTO [title=" + title + ", price=" + price + "]"; + } + } From 8e25ec55bf85872414626c00d0597498a45aca42 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Wed, 21 Jun 2017 23:35:53 +0000 Subject: [PATCH 291/492] change long with BigIntger and replace getBook() --- .../main/java/com/iluwatar/cqrs/queries/IQueryService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java index 3cf4a2945..3abf2ec16 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java @@ -1,5 +1,6 @@ package com.iluwatar.cqrs.queries; +import java.math.BigInteger; import java.util.List; import com.iluwatar.cqrs.dto.AuthorDTO; @@ -9,12 +10,12 @@ public interface IQueryService { public abstract AuthorDTO getAuthorByUsername(String username); - public abstract Double getBookPrice(String title); + public abstract BookDTO getBook(String title); public abstract List getAuthorBooks(String username); - public abstract long getAuthorBooksCount(String username); + public abstract BigInteger getAuthorBooksCount(String username); - public abstract long getAuthorsCount(); + public abstract BigInteger getAuthorsCount(); } From 40c00ca2af33145282f18a5d98f0dea9530f35b2 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Wed, 21 Jun 2017 23:36:39 +0000 Subject: [PATCH 292/492] add ICommandService and IQueriesService Implementations --- .../cqrs/commandes/CommandServiceImpl.java | 111 ++++++++++++++++++ .../cqrs/queries/QueryServiceImpl.java | 74 ++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java create mode 100644 cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java new file mode 100644 index 000000000..6fd2e2900 --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java @@ -0,0 +1,111 @@ +package com.iluwatar.cqrs.commandes; + +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; + +import com.iluwatar.cqrs.domain.model.Author; +import com.iluwatar.cqrs.domain.model.Book; +import com.iluwatar.cqrs.util.HibernateUtil; + +public class CommandServiceImpl implements ICommandService { + + private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); + + private Author getAuthorByUsername(String username) { + Session session = sessionFactory.openSession(); + Query query = session.createQuery("from Author where username=:username"); + query.setParameter("username", username); + Author author = (Author) query.uniqueResult(); + session.close(); + return author; + } + + private Book getBookByTitle(String title) { + Session session = sessionFactory.openSession(); + Query query = session.createQuery("from Book where title=:title"); + query.setParameter("title", title); + Book book = (Book) query.uniqueResult(); + session.close(); + return book; + } + + @Override + public void authorCreated(String username, String name, String email) { + Author author = new Author(username, name, email); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.save(author); + session.getTransaction().commit(); + session.close(); + } + + @Override + public void bookAddedToAuthor(String title, double price, String username) { + Author author = getAuthorByUsername(username); + Book book = new Book(title, price, author); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.save(book); + session.getTransaction().commit(); + session.close(); + } + + @Override + public void authorNameUpdated(String username, String name) { + Author author = getAuthorByUsername(username); + author.setName(name); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.update(author); + session.getTransaction().commit(); + session.close(); + } + + @Override + public void authorUsernameUpdated(String oldUsername, String newUsername) { + Author author = getAuthorByUsername(oldUsername); + author.setUsername(newUsername); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.update(author); + session.getTransaction().commit(); + session.close(); + + } + + @Override + public void authorEmailUpdated(String username, String email) { + Author author = getAuthorByUsername(username); + author.setEmail(email); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.update(author); + session.getTransaction().commit(); + session.close(); + + } + + @Override + public void bookTitleUpdated(String oldTitle, String newTitle) { + Book book = getBookByTitle(oldTitle); + book.setTitle(newTitle); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.update(book); + session.getTransaction().commit(); + session.close(); + } + + @Override + public void bookPriceUpdated(String title, double price) { + Book book = getBookByTitle(title); + book.setPrice(price); + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session.update(book); + session.getTransaction().commit(); + session.close(); + } + +} diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java new file mode 100644 index 000000000..b383a850b --- /dev/null +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java @@ -0,0 +1,74 @@ +package com.iluwatar.cqrs.queries; + +import java.math.BigInteger; +import java.util.List; + +import org.hibernate.SQLQuery; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.transform.Transformers; + +import com.iluwatar.cqrs.dto.AuthorDTO; +import com.iluwatar.cqrs.dto.BookDTO; +import com.iluwatar.cqrs.util.HibernateUtil; + +public class QueryServiceImpl implements IQueryService { + + private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); + + @Override + public AuthorDTO getAuthorByUsername(String username) { + Session session = sessionFactory.openSession(); + SQLQuery sqlQuery = session + .createSQLQuery("SELECT a.username as \"username\", a.name as \"name\", a.email as \"email\"" + + "FROM Author a where a.username=:username"); + sqlQuery.setParameter("username", username); + AuthorDTO authorDTO = (AuthorDTO) sqlQuery.setResultTransformer(Transformers.aliasToBean(AuthorDTO.class)) + .uniqueResult(); + session.close(); + return authorDTO; + } + + @Override + public BookDTO getBook(String title) { + Session session = sessionFactory.openSession(); + SQLQuery sqlQuery = session + .createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + " FROM Book b where b.title=:title"); + sqlQuery.setParameter("title", title); + BookDTO bookDTO = (BookDTO) sqlQuery.setResultTransformer(Transformers.aliasToBean(BookDTO.class)).uniqueResult(); + session.close(); + return bookDTO; + } + + @Override + public List getAuthorBooks(String username) { + Session session = sessionFactory.openSession(); + SQLQuery sqlQuery = session.createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + + " FROM Author a , Book b where b.author_id = a.id and a.username=:username"); + sqlQuery.setParameter("username", username); + List bookDTOs = sqlQuery.setResultTransformer(Transformers.aliasToBean(BookDTO.class)).list(); + session.close(); + return bookDTOs; + } + + @Override + public BigInteger getAuthorBooksCount(String username) { + Session session = sessionFactory.openSession(); + SQLQuery sqlQuery = session.createSQLQuery( + "SELECT count(b.title)" + " FROM Book b, Author a where b.author_id = a.id and a.username=:username"); + sqlQuery.setParameter("username", username); + BigInteger bookcount = (BigInteger) sqlQuery.uniqueResult(); + session.close(); + return bookcount; + } + + @Override + public BigInteger getAuthorsCount() { + Session session = sessionFactory.openSession(); + SQLQuery sqlQuery = session.createSQLQuery("SELECT count(id) from Author"); + BigInteger authorcount = (BigInteger) sqlQuery.uniqueResult(); + session.close(); + return authorcount; + } + +} From a2dba5bf6d9462ed54e5be67d1790fa022c9985e Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Thu, 22 Jun 2017 23:56:57 +0000 Subject: [PATCH 293/492] add logs, javadoc and format to checkstyle conventions --- .../cqrs/commandes/CommandServiceImpl.java | 4 +++ .../cqrs/commandes/ICommandService.java | 4 +++ .../iluwatar/cqrs/domain/model/Author.java | 6 ++-- .../com/iluwatar/cqrs/domain/model/Book.java | 6 ++-- .../cqrs/dto/{AuthorDTO.java => Author.java} | 20 +++++++++++-- .../cqrs/dto/{BookDTO.java => Book.java} | 18 ++++++++++-- .../iluwatar/cqrs/queries/IQueryService.java | 15 ++++++---- .../cqrs/queries/QueryServiceImpl.java | 28 +++++++++++-------- .../com/iluwatar/cqrs/util/HibernateUtil.java | 18 ++++++------ cqrs/src/main/resources/hibernate.cfg.xml | 18 ++++++------ cqrs/src/main/resources/logback.xml | 13 +++++++++ 11 files changed, 105 insertions(+), 45 deletions(-) rename cqrs/src/main/java/com/iluwatar/cqrs/dto/{AuthorDTO.java => Author.java} (56%) rename cqrs/src/main/java/com/iluwatar/cqrs/dto/{BookDTO.java => Book.java} (55%) create mode 100644 cqrs/src/main/resources/logback.xml diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java index 6fd2e2900..18a80dc16 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java @@ -8,6 +8,10 @@ import com.iluwatar.cqrs.domain.model.Author; import com.iluwatar.cqrs.domain.model.Book; import com.iluwatar.cqrs.util.HibernateUtil; +/** + * This class is implementation of {@link ICommandService} interface. It uses Hibernate as an api for persistence. + * + */ public class CommandServiceImpl implements ICommandService { private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java index 4ccb0f456..d752a107e 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java @@ -1,5 +1,9 @@ package com.iluwatar.cqrs.commandes; +/** + * This interface represents the commands of the CQRS pattern + * + */ public interface ICommandService { public abstract void authorCreated(String username, String name, String email); diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java index 5008a233a..308fb4f5d 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java @@ -6,8 +6,7 @@ import javax.persistence.GenerationType; import javax.persistence.Id; /** - * - * @author Sabiq Ihab + * This is an Author entity. It is used by Hibernate for persistence. * */ @Entity @@ -22,8 +21,11 @@ public class Author { /** * * @param username + * username of the author * @param name + * name of the author * @param email + * email of the author */ public Author(String username, String name, String email) { super(); diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java index 6c04f2bf5..3d14fae47 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java @@ -7,8 +7,7 @@ import javax.persistence.Id; import javax.persistence.ManyToOne; /** - * - * @author Sabiq Ihab + * This is a Book entity. It is used by Hibernate for persistence. Many books can be written by one {@link Author} * */ @Entity @@ -24,8 +23,11 @@ public class Book { /** * * @param title + * title of the book * @param price + * price of the book * @param author + * author of the book */ public Book(String title, double price, Author author) { super(); diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/AuthorDTO.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java similarity index 56% rename from cqrs/src/main/java/com/iluwatar/cqrs/dto/AuthorDTO.java rename to cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java index a6ce20912..53bc22d1f 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/dto/AuthorDTO.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java @@ -1,19 +1,33 @@ package com.iluwatar.cqrs.dto; -public class AuthorDTO { +/** + * + * This is a DTO (Data Transfer Object) author, contains only useful information to be returned + * + */ +public class Author { private String name; private String email; private String username; - public AuthorDTO(String name, String email, String username) { + /** + * + * @param name + * name of the author + * @param email + * email of the author + * @param username + * username of the author + */ + public Author(String name, String email, String username) { super(); this.name = name; this.email = email; this.username = username; } - public AuthorDTO() { + public Author() { super(); } diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java similarity index 55% rename from cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java rename to cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java index aa015d01b..1d4282cd5 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/dto/BookDTO.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java @@ -1,17 +1,29 @@ package com.iluwatar.cqrs.dto; -public class BookDTO { +/** + * + * This is a DTO (Data Transfer Object) book, contains only useful information to be returned + * + */ +public class Book { private String title; private double price; - public BookDTO(String title, double price) { + /** + * + * @param title + * title of the book + * @param price + * price of the book + */ + public Book(String title, double price) { super(); this.title = title; this.price = price; } - public BookDTO() { + public Book() { super(); } diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java index 3abf2ec16..255796d89 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java @@ -3,16 +3,21 @@ package com.iluwatar.cqrs.queries; import java.math.BigInteger; import java.util.List; -import com.iluwatar.cqrs.dto.AuthorDTO; -import com.iluwatar.cqrs.dto.BookDTO; +import com.iluwatar.cqrs.dto.Author; +import com.iluwatar.cqrs.dto.Book; +/** + * + * This interface represents the query methods of the CQRS pattern + * + */ public interface IQueryService { - public abstract AuthorDTO getAuthorByUsername(String username); + public abstract Author getAuthorByUsername(String username); - public abstract BookDTO getBook(String title); + public abstract Book getBook(String title); - public abstract List getAuthorBooks(String username); + public abstract List getAuthorBooks(String username); public abstract BigInteger getAuthorBooksCount(String username); diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java index b383a850b..55a40c277 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java @@ -8,47 +8,51 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.transform.Transformers; -import com.iluwatar.cqrs.dto.AuthorDTO; -import com.iluwatar.cqrs.dto.BookDTO; +import com.iluwatar.cqrs.dto.Author; +import com.iluwatar.cqrs.dto.Book; import com.iluwatar.cqrs.util.HibernateUtil; +/** + * This class is an implementation of {@link IQueryService}. It uses Hibernate native queries to return DTOs from the + * database. + * + */ public class QueryServiceImpl implements IQueryService { private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); @Override - public AuthorDTO getAuthorByUsername(String username) { + public Author getAuthorByUsername(String username) { Session session = sessionFactory.openSession(); SQLQuery sqlQuery = session .createSQLQuery("SELECT a.username as \"username\", a.name as \"name\", a.email as \"email\"" + "FROM Author a where a.username=:username"); sqlQuery.setParameter("username", username); - AuthorDTO authorDTO = (AuthorDTO) sqlQuery.setResultTransformer(Transformers.aliasToBean(AuthorDTO.class)) - .uniqueResult(); + Author authorDTo = (Author) sqlQuery.setResultTransformer(Transformers.aliasToBean(Author.class)).uniqueResult(); session.close(); - return authorDTO; + return authorDTo; } @Override - public BookDTO getBook(String title) { + public Book getBook(String title) { Session session = sessionFactory.openSession(); SQLQuery sqlQuery = session .createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + " FROM Book b where b.title=:title"); sqlQuery.setParameter("title", title); - BookDTO bookDTO = (BookDTO) sqlQuery.setResultTransformer(Transformers.aliasToBean(BookDTO.class)).uniqueResult(); + Book bookDTo = (Book) sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).uniqueResult(); session.close(); - return bookDTO; + return bookDTo; } @Override - public List getAuthorBooks(String username) { + public List getAuthorBooks(String username) { Session session = sessionFactory.openSession(); SQLQuery sqlQuery = session.createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + " FROM Author a , Book b where b.author_id = a.id and a.username=:username"); sqlQuery.setParameter("username", username); - List bookDTOs = sqlQuery.setResultTransformer(Transformers.aliasToBean(BookDTO.class)).list(); + List bookDTos = sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).list(); session.close(); - return bookDTOs; + return bookDTos; } @Override diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java b/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java index 9e19e05d4..c8f41762e 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java @@ -4,27 +4,27 @@ import org.hibernate.SessionFactory; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * - * @author Sabiq Ihab + * This class simply returns one instance of {@link SessionFactory} initialized when the application is started * */ public class HibernateUtil { private static final SessionFactory SESSIONFACTORY = buildSessionFactory(); + private static final Logger LOGGER = LoggerFactory.getLogger(HibernateUtil.class); private static SessionFactory buildSessionFactory() { - // A SessionFactory is set up once for an application! - final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure() // configures settings // - // from hibernate.cfg.xml - .build(); + + // configures settings from hibernate.cfg.xml + final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build(); try { return new MetadataSources(registry).buildMetadata().buildSessionFactory(); - } catch (Throwable ex) { + } catch (Exception ex) { StandardServiceRegistryBuilder.destroy(registry); - // TODO HibernateUtil : change print with logger - System.err.println("Initial SessionFactory creation failed." + ex); + LOGGER.error("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } diff --git a/cqrs/src/main/resources/hibernate.cfg.xml b/cqrs/src/main/resources/hibernate.cfg.xml index a6ca21983..151983337 100644 --- a/cqrs/src/main/resources/hibernate.cfg.xml +++ b/cqrs/src/main/resources/hibernate.cfg.xml @@ -3,13 +3,13 @@ "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> - - org.hibernate.dialect.H2Dialect - org.h2.Driver - jdbc:h2:mem:test - sa - create - - - + + org.hibernate.dialect.H2Dialect + org.h2.Driver + jdbc:h2:mem:test + sa + create + + + \ No newline at end of file diff --git a/cqrs/src/main/resources/logback.xml b/cqrs/src/main/resources/logback.xml new file mode 100644 index 000000000..6b5d24345 --- /dev/null +++ b/cqrs/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + From 3128d3fb40bf9fad1f163b7542a97c3ae7b194d8 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Fri, 23 Jun 2017 00:12:30 +0000 Subject: [PATCH 294/492] create main class --- .../main/java/com/iluwatar/cqrs/app/App.java | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java index c472e2772..0fac42e69 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java @@ -1,10 +1,54 @@ package com.iluwatar.cqrs.app; +import java.math.BigInteger; +import java.util.List; + +import com.iluwatar.cqrs.commandes.CommandServiceImpl; +import com.iluwatar.cqrs.commandes.ICommandService; +import com.iluwatar.cqrs.dto.Author; +import com.iluwatar.cqrs.dto.Book; +import com.iluwatar.cqrs.queries.IQueryService; +import com.iluwatar.cqrs.queries.QueryServiceImpl; +import com.iluwatar.cqrs.util.HibernateUtil; + +/** + * This is the entry of the application + * + */ public class App { - + /** + * Program entry point + * + * @param args + * command line args + */ public static void main(String[] args) { - // TODO Auto-generated method stub + ICommandService commands = new CommandServiceImpl(); + // Create Authors and Books using CommandService + commands.authorCreated("eEvans", "Eric Evans", "eEvans@email.com"); + commands.authorCreated("jBloch", "Joshua Bloch", "jBloch@email.com"); + commands.authorCreated("mFowler", "Martin Fowler", "mFowler@email.com"); + + commands.bookAddedToAuthor("Domain-Driven Design", 60.08, "eEvans"); + commands.bookAddedToAuthor("Effective Java", 40.54, "jBloch"); + commands.bookAddedToAuthor("Java Puzzlers", 39.99, "jBloch"); + commands.bookAddedToAuthor("Java Concurrency in Practice", 29.40, "jBloch"); + commands.bookAddedToAuthor("Patterns of Enterprise Application Architecture", 54.01, "mFowler"); + commands.bookAddedToAuthor("Domain Specific Languages", 48.89, "mFowler"); + commands.authorNameUpdated("eEvans", "Eric J. Evans"); + + IQueryService queries = new QueryServiceImpl(); + + // Query the database using QueryService + Author nullAuthor = queries.getAuthorByUsername("username"); + Author eEvans = queries.getAuthorByUsername("eEvans"); + BigInteger jBlochBooksCount = queries.getAuthorBooksCount("jBloch"); + BigInteger authorsCount = queries.getAuthorsCount(); + Book dddBook = queries.getBook("Domain-Driven Design"); + List jBlochBooks = queries.getAuthorBooks("jBloch"); + + HibernateUtil.getSessionFactory().close(); } } From a8f50297ebbc2f94b1998817bc3a91642c70785d Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 24 Jun 2017 00:31:04 +0000 Subject: [PATCH 295/492] add hashCode and equals to Author and Book DTOs --- .../java/com/iluwatar/cqrs/dto/Author.java | 20 +++++++++++++++++++ .../main/java/com/iluwatar/cqrs/dto/Book.java | 19 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java index 53bc22d1f..b7a7ae880 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java @@ -1,5 +1,7 @@ package com.iluwatar.cqrs.dto; +import java.util.Objects; + /** * * This is a DTO (Data Transfer Object) author, contains only useful information to be returned @@ -48,4 +50,22 @@ public class Author { return "AuthorDTO [name=" + name + ", email=" + email + ", username=" + username + "]"; } + @Override + public int hashCode() { + return Objects.hash(username, name, email); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Author)) { + return false; + } + Author other = (Author) obj; + return username.equals(other.getUsername()) && email.equals(other.getEmail()) && name.equals(other.getName()); + + } + } diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java index 1d4282cd5..b3f0f62d3 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java @@ -1,5 +1,7 @@ package com.iluwatar.cqrs.dto; +import java.util.Objects; + /** * * This is a DTO (Data Transfer Object) book, contains only useful information to be returned @@ -40,4 +42,21 @@ public class Book { return "BookDTO [title=" + title + ", price=" + price + "]"; } + @Override + public int hashCode() { + return Objects.hash(title, price); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Book)) { + return false; + } + Book book = (Book) obj; + return title.equals(book.getTitle()) && price == book.getPrice(); + } + } From b67719ab329f51731664dff9f0dbaf79306674b5 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 24 Jun 2017 00:31:43 +0000 Subject: [PATCH 296/492] add tests --- .../main/java/com/iluwatar/cqrs/app/App.java | 25 ++++- .../test/java/com/iluwatar/cqrs/AppTest.java | 11 +- .../com/iluwatar/cqrs/IntegrationTest.java | 100 ++++++++++++++++++ cqrs/src/test/resources/hibernate.cfg.xml | 15 +++ cqrs/src/test/resources/logback.xml | 13 +++ 5 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java create mode 100644 cqrs/src/test/resources/hibernate.cfg.xml create mode 100644 cqrs/src/test/resources/logback.xml diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java index 0fac42e69..063d237e0 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.cqrs.app; import java.math.BigInteger; @@ -12,7 +34,8 @@ import com.iluwatar.cqrs.queries.QueryServiceImpl; import com.iluwatar.cqrs.util.HibernateUtil; /** - * This is the entry of the application + * CQRS : Command Query Responsibility Segregation. A pattern used to separate query services from commands or writes + * services. * */ public class App { diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java b/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java index ce9181370..ad1cf490b 100644 --- a/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java +++ b/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java @@ -1,14 +1,19 @@ package com.iluwatar.cqrs; -import static org.junit.Assert.*; - import org.junit.Test; +import com.iluwatar.cqrs.app.App; + +/** + * Application test + * + */ public class AppTest { @Test public void test() { - fail("Not yet implemented"); + String[] args = {}; + App.main(args); } } diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java b/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java new file mode 100644 index 000000000..204aa08bc --- /dev/null +++ b/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java @@ -0,0 +1,100 @@ +package com.iluwatar.cqrs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.iluwatar.cqrs.commandes.CommandServiceImpl; +import com.iluwatar.cqrs.commandes.ICommandService; +import com.iluwatar.cqrs.dto.Author; +import com.iluwatar.cqrs.dto.Book; +import com.iluwatar.cqrs.queries.IQueryService; +import com.iluwatar.cqrs.queries.QueryServiceImpl; +import com.iluwatar.cqrs.util.HibernateUtil; + +/** + * Integration test of IQueryService and ICommandService with h2 data + * + */ +public class IntegrationTest { + + private static IQueryService queryService; + private static ICommandService commandService; + + @BeforeClass + public static void initialize() { + commandService = new CommandServiceImpl(); + queryService = new QueryServiceImpl(); + } + + @BeforeClass + public static void populateDatabase() { + // create first author1 + commandService.authorCreated("username1", "name1", "email1"); + + // create author1 and update all its data + commandService.authorCreated("username2", "name2", "email2"); + commandService.authorEmailUpdated("username2", "new_email2"); + commandService.authorNameUpdated("username2", "new_name2"); + commandService.authorUsernameUpdated("username2", "new_username2"); + + // add book1 to author1 + commandService.bookAddedToAuthor("title1", 10, "username1"); + + // add book2 to author1 and update all its data + commandService.bookAddedToAuthor("title2", 20, "username1"); + commandService.bookPriceUpdated("title2", 30); + commandService.bookTitleUpdated("title2", "new_title2"); + + } + + @Test + public void testGetAuthorByUsername() { + Author author = queryService.getAuthorByUsername("username1"); + assertEquals("username1", author.getUsername()); + assertEquals("name1", author.getName()); + assertEquals("email1", author.getEmail()); + } + + @Test + public void testGetUpdatedAuthorByUsername() { + Author author = queryService.getAuthorByUsername("new_username2"); + Author expectedAuthor = new Author("new_name2", "new_email2", "new_username2"); + assertEquals(expectedAuthor, author); + + } + + @Test + public void testGetBook() { + Book book = queryService.getBook("title1"); + assertEquals("title1", book.getTitle()); + assertEquals(10, book.getPrice(), 0); + } + + @Test + public void testGetAuthorBooks() { + List books = queryService.getAuthorBooks("username1"); + assertTrue(books.size() == 2); + assertTrue(books.contains(new Book("title1", 10))); + assertTrue(books.contains(new Book("new_title2", 30))); + } + + @Test + public void testGetAuthorBooksCount() { + BigInteger bookCount = queryService.getAuthorBooksCount("username1"); + assertEquals(new BigInteger("2"), bookCount); + } + + @Test + public void testGetAuthorsCount() { + BigInteger authorCount = queryService.getAuthorsCount(); + assertEquals(new BigInteger("2"), authorCount); + } + +} diff --git a/cqrs/src/test/resources/hibernate.cfg.xml b/cqrs/src/test/resources/hibernate.cfg.xml new file mode 100644 index 000000000..151983337 --- /dev/null +++ b/cqrs/src/test/resources/hibernate.cfg.xml @@ -0,0 +1,15 @@ + + + + + + org.hibernate.dialect.H2Dialect + org.h2.Driver + jdbc:h2:mem:test + sa + create + + + + \ No newline at end of file diff --git a/cqrs/src/test/resources/logback.xml b/cqrs/src/test/resources/logback.xml new file mode 100644 index 000000000..6b5d24345 --- /dev/null +++ b/cqrs/src/test/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + From d8919d88f08ba40f94185da58a19e2a801ab2fc7 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Fri, 30 Jun 2017 20:30:19 +0000 Subject: [PATCH 297/492] fix pmd errors --- cqrs/src/main/java/com/iluwatar/cqrs/app/App.java | 7 +++++++ .../iluwatar/cqrs/commandes/ICommandService.java | 14 +++++++------- .../com/iluwatar/cqrs/queries/IQueryService.java | 10 +++++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java index 063d237e0..02c4bed3c 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java @@ -71,6 +71,13 @@ public class App { Book dddBook = queries.getBook("Domain-Driven Design"); List jBlochBooks = queries.getAuthorBooks("jBloch"); + System.out.println("Author username : " + nullAuthor); + System.out.println("Author eEvans : " + eEvans); + System.out.println("jBloch number of books : " + jBlochBooksCount); + System.out.println("Number of authors : " + authorsCount); + System.out.println("DDD book : " + dddBook); + System.out.println("jBloch books : " + jBlochBooks); + HibernateUtil.getSessionFactory().close(); } diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java index d752a107e..eb3cc43a1 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java @@ -6,18 +6,18 @@ package com.iluwatar.cqrs.commandes; */ public interface ICommandService { - public abstract void authorCreated(String username, String name, String email); + void authorCreated(String username, String name, String email); - public abstract void bookAddedToAuthor(String title, double price, String username); + void bookAddedToAuthor(String title, double price, String username); - public abstract void authorNameUpdated(String username, String name); + void authorNameUpdated(String username, String name); - public abstract void authorUsernameUpdated(String oldUsername, String newUsername); + void authorUsernameUpdated(String oldUsername, String newUsername); - public abstract void authorEmailUpdated(String username, String email); + void authorEmailUpdated(String username, String email); - public abstract void bookTitleUpdated(String oldTitle, String newTitle); + void bookTitleUpdated(String oldTitle, String newTitle); - public abstract void bookPriceUpdated(String title, double price); + void bookPriceUpdated(String title, double price); } diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java index 255796d89..3e3d6ab10 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java @@ -13,14 +13,14 @@ import com.iluwatar.cqrs.dto.Book; */ public interface IQueryService { - public abstract Author getAuthorByUsername(String username); + Author getAuthorByUsername(String username); - public abstract Book getBook(String title); + Book getBook(String title); - public abstract List getAuthorBooks(String username); + List getAuthorBooks(String username); - public abstract BigInteger getAuthorBooksCount(String username); + BigInteger getAuthorBooksCount(String username); - public abstract BigInteger getAuthorsCount(); + BigInteger getAuthorsCount(); } From 5873aeeb699940f05f2c4637934779537cd8e8f1 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Fri, 30 Jun 2017 21:27:15 +0000 Subject: [PATCH 298/492] add cqrs module to parent pom.xml and update pom.xml --- cqrs/pom.xml | 2 +- pom.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cqrs/pom.xml b/cqrs/pom.xml index df5a8a48f..6c036a933 100644 --- a/cqrs/pom.xml +++ b/cqrs/pom.xml @@ -21,7 +21,7 @@ com.iluwatar java-design-patterns - 1.16.0-SNAPSHOT + 1.17.0-SNAPSHOT cqrs diff --git a/pom.xml b/pom.xml index 3653a6fe0..4f4b5dee6 100644 --- a/pom.xml +++ b/pom.xml @@ -142,6 +142,7 @@ balking extension-objects marker + cqrs From c744bf418a812c8fea50a67cf2dce8f454c09bac Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Fri, 30 Jun 2017 21:41:01 +0000 Subject: [PATCH 299/492] add README.md, cqrs.ucls and etc/cqrs.urm.puml --- cqrs/README.md | 29 ++++++++++ cqrs/etc/cqrs.png | Bin 0 -> 105666 bytes cqrs/etc/cqrs.ucls | 107 ++++++++++++++++++++++++++++++++++- cqrs/etc/cqrs.urm.puml | 124 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 cqrs/etc/cqrs.png create mode 100644 cqrs/etc/cqrs.urm.puml diff --git a/cqrs/README.md b/cqrs/README.md index e69de29bb..d7463715c 100644 --- a/cqrs/README.md +++ b/cqrs/README.md @@ -0,0 +1,29 @@ +--- +layout: pattern +title: CQRS +folder: cqrs +permalink: /patterns/cqrs/ +pumlid: +categories: Architectural +tags: + - Java + - Difficulty-Intermediate +--- + +## Intent +CQRS Command Query Responsibility Segregation - Seperate the query side from the command side. + +![alt text](./etc/cqrs.png "CQRS") + +## Applicability +Use the CQRS pattern when + +* you want to scale the queries and commands independently. +* you want to use different data models for queries and commands. Useful when dealing with complex domains. +* you want to use architectures like event sourcing or task based UI. + +## Credits + +* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683) +* [Martin Fowler - CQRS](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/) +* [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw) diff --git a/cqrs/etc/cqrs.png b/cqrs/etc/cqrs.png new file mode 100644 index 0000000000000000000000000000000000000000..28174bc9ab8ef388ca5142e26e54d0f9e3bab635 GIT binary patch literal 105666 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ℑLH=hIn`f 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 + associations="true" dependencies="false" nesting-relationships="true" router="FAN"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cqrs/etc/cqrs.urm.puml b/cqrs/etc/cqrs.urm.puml new file mode 100644 index 000000000..6dd65dd3a --- /dev/null +++ b/cqrs/etc/cqrs.urm.puml @@ -0,0 +1,124 @@ +@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 { + + 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) + + equals(obj : Object) : boolean + + getEmail() : String + + getName() : String + + getUsername() : String + + hashCode() : int + + toString() : String + } + class Book { + - price : double + - title : String + + Book() + + Book(title : String, price : double) + + equals(obj : Object) : boolean + + getPrice() : double + + getTitle() : String + + hashCode() : int + + toString() : String + } +} +package com.iluwatar.cqrs.commandes { + 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 + } + interface ICommandService { + + 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} + } +} +package com.iluwatar.cqrs.queries { + interface IQueryService { + + 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.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 ..|> ICommandService +QueryServiceImpl ..|> IQueryService +@enduml \ No newline at end of file From d1b11539ec6e20a7e0e28824379993c6f25f1d28 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Fri, 30 Jun 2017 21:53:47 +0000 Subject: [PATCH 300/492] add pumlid --- cqrs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cqrs/README.md b/cqrs/README.md index d7463715c..216953cf0 100644 --- a/cqrs/README.md +++ b/cqrs/README.md @@ -3,7 +3,7 @@ layout: pattern title: CQRS folder: cqrs permalink: /patterns/cqrs/ -pumlid: +pumlid: 7SPR4a0m3030gt00pR_RH6I8QQFouFgC_TfHb6gkd5Q7FQBx363ub4rYpoMTZKuDrYXqDX37HIuuyCPfPPTDfuuHREhGqBy0NUR0GNzAMYizMtq1 categories: Architectural tags: - Java From 87c10faaacdf533233a69edf5f4e9c2ed7de6fb9 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Fri, 30 Jun 2017 23:21:40 +0000 Subject: [PATCH 301/492] Fix : remove AppTest --- .../test/java/com/iluwatar/cqrs/AppTest.java | 19 ------------------- .../com/iluwatar/cqrs/IntegrationTest.java | 2 -- 2 files changed, 21 deletions(-) delete mode 100644 cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java b/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java deleted file mode 100644 index ad1cf490b..000000000 --- a/cqrs/src/test/java/com/iluwatar/cqrs/AppTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.iluwatar.cqrs; - -import org.junit.Test; - -import com.iluwatar.cqrs.app.App; - -/** - * Application test - * - */ -public class AppTest { - - @Test - public void test() { - String[] args = {}; - App.main(args); - } - -} diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java b/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java index 204aa08bc..c9e3b36f4 100644 --- a/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java +++ b/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java @@ -6,7 +6,6 @@ import static org.junit.Assert.assertTrue; import java.math.BigInteger; import java.util.List; -import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -16,7 +15,6 @@ import com.iluwatar.cqrs.dto.Author; import com.iluwatar.cqrs.dto.Book; import com.iluwatar.cqrs.queries.IQueryService; import com.iluwatar.cqrs.queries.QueryServiceImpl; -import com.iluwatar.cqrs.util.HibernateUtil; /** * Integration test of IQueryService and ICommandService with h2 data From c6b6c8123fb1add1f469cf8d572375309fcdb48c Mon Sep 17 00:00:00 2001 From: "mahendran.mookkiah" Date: Sat, 22 Jul 2017 18:35:18 -0400 Subject: [PATCH 302/492] #587 sonarqube bugs --- .../iluwatar/intercepting/filter/Client.java | 41 ++++++++----------- .../intercepting/filter/FilterChain.java | 5 --- .../iluwatar/intercepting/filter/Order.java | 12 +++--- .../intercepting/filter/OrderFilter.java | 2 +- .../iluwatar/intercepting/filter/Target.java | 2 +- .../intercepting/filter/OrderTest.java | 4 +- 6 files changed, 26 insertions(+), 40 deletions(-) diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java index f404ee046..60b888dc7 100644 --- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java +++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java @@ -24,8 +24,6 @@ package com.iluwatar.intercepting.filter; import java.awt.BorderLayout; import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; @@ -37,20 +35,20 @@ import javax.swing.JTextField; import javax.swing.SwingUtilities; /** - * The Client class is responsible for handling the input and running them through filters inside - * the {@link FilterManager}. + * The Client class is responsible for handling the input and running them through filters inside the + * {@link FilterManager}. * - * This is where {@link Filter}s come to play as the client pre-processes the request before being - * displayed in the {@link Target}. + * This is where {@link Filter}s come to play as the client pre-processes the request before being displayed in the + * {@link Target}. * * @author joshzambales * */ -public class Client extends JFrame { +public class Client extends JFrame { // NOSONAR private static final long serialVersionUID = 1L; - private FilterManager filterManager; + private transient FilterManager filterManager; private JLabel jl; private JTextField[] jtFields; private JTextArea[] jtAreas; @@ -98,26 +96,19 @@ public class Client extends JFrame { panel.add(clearButton); panel.add(processButton); - clearButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - for (JTextArea i : jtAreas) { - i.setText(""); - } - for (JTextField i : jtFields) { - i.setText(""); - } + clearButton.addActionListener(e -> { + for (JTextArea i : jtAreas) { + i.setText(""); + } + for (JTextField i : jtFields) { + i.setText(""); } }); - processButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Order order = - new Order(jtFields[0].getText(), jtFields[1].getText(), jtAreas[0].getText(), - jtFields[2].getText(), jtAreas[1].getText()); - jl.setText(sendRequest(order)); - } + processButton.addActionListener(e -> { + Order order = new Order(jtFields[0].getText(), jtFields[1].getText(), jtAreas[0].getText(), jtFields[2].getText(), + jtAreas[1].getText()); + jl.setText(sendRequest(order)); }); JRootPane rootPane = SwingUtilities.getRootPane(processButton); diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java index 7012fb273..1e0c0de35 100644 --- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java +++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java @@ -32,11 +32,6 @@ public class FilterChain { private Filter chain; - /** - * Constructor - */ - public FilterChain() { - } /** * Adds filter diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java index c74cd1b00..c29898652 100644 --- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java +++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java @@ -32,7 +32,7 @@ public class Order { private String contactNumber; private String address; private String depositNumber; - private String order; + private String orderItem; public Order() {} @@ -44,7 +44,7 @@ public class Order { this.contactNumber = contactNumber; this.address = address; this.depositNumber = depositNumber; - this.order = order; + this.orderItem = order; } public String getName() { @@ -79,11 +79,11 @@ public class Order { this.depositNumber = depositNumber; } - public String getOrder() { - return order; + public String getOrderItem() { + return orderItem; } - public void setOrder(String order) { - this.order = order; + public void setOrderItem(String order) { + this.orderItem = order; } } diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/OrderFilter.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/OrderFilter.java index 8c2ec4d9f..bc9ff7d90 100644 --- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/OrderFilter.java +++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/OrderFilter.java @@ -33,7 +33,7 @@ public class OrderFilter extends AbstractFilter { @Override public String execute(Order order) { String result = super.execute(order); - if (order.getOrder() == null || order.getOrder().isEmpty()) { + if (order.getOrderItem() == null || order.getOrderItem().isEmpty()) { return result + "Invalid order! "; } else { return result; diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java index 803c0d5c6..6652d1eb4 100644 --- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java +++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java @@ -42,7 +42,7 @@ import javax.swing.table.DefaultTableModel; * @author mjoshzambales * */ -public class Target extends JFrame { +public class Target extends JFrame { //NOSONAR private static final long serialVersionUID = 1L; diff --git a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/OrderTest.java b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/OrderTest.java index 9148cc84c..f52f6deec 100644 --- a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/OrderTest.java +++ b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/OrderTest.java @@ -66,8 +66,8 @@ public class OrderTest { @Test public void testSetOrder() throws Exception { final Order order = new Order(); - order.setOrder(EXPECTED_VALUE); - assertEquals(EXPECTED_VALUE, order.getOrder()); + order.setOrderItem(EXPECTED_VALUE); + assertEquals(EXPECTED_VALUE, order.getOrderItem()); } } From 9b1a9aafc1c9005d17efe4f1f97f0d26b51b31af Mon Sep 17 00:00:00 2001 From: Kevin Woodland Date: Fri, 28 Jul 2017 20:20:38 +0200 Subject: [PATCH 303/492] Update README.md punctuation and spelling Fixed minor punctuation and spelling while reading through applicability --- tls/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tls/README.md b/tls/README.md index 904d7ee05..02d889f50 100644 --- a/tls/README.md +++ b/tls/README.md @@ -18,5 +18,5 @@ Securing variables global to a thread against being spoiled by other threads. Th ## Applicability Use the Thread Local Storage in any of the following situations -* when you use class variables in your Callable / Runnalbe object that are not read-only and you use the same Callable instance in more than one thread running in parallel +* when you use class variables in your Callable / Runnable object that are not read-only and you use the same Callable instance in more than one thread running in parallel. * when you use static variables in your Callable / Runnable object that are not read-only and more than one instances of the Callable / Runnalbe may run in parallel threads. From 8073b93182f0cc8600685edb404479aaf00f58e1 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 29 Jul 2017 12:04:04 +0100 Subject: [PATCH 304/492] fix README.md --- cqrs/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cqrs/README.md b/cqrs/README.md index 216953cf0..3cdd429a1 100644 --- a/cqrs/README.md +++ b/cqrs/README.md @@ -11,7 +11,7 @@ tags: --- ## Intent -CQRS Command Query Responsibility Segregation - Seperate the query side from the command side. +CQRS Command Query Responsibility Segregation - Separate the query side from the command side. ![alt text](./etc/cqrs.png "CQRS") @@ -24,6 +24,6 @@ Use the CQRS pattern when ## Credits -* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683) -* [Martin Fowler - CQRS](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/) +* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/) +* [Martin Fowler - CQRS](https://martinfowler.com/bliki/CQRS.html) * [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw) From 8bf4497879447a01cc800a64825a4c5e18b2e646 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 29 Jul 2017 12:13:34 +0100 Subject: [PATCH 305/492] Close sessions using try with resources --- .../cqrs/commandes/CommandServiceImpl.java | 96 +++++++++---------- .../cqrs/queries/QueryServiceImpl.java | 63 ++++++------ 2 files changed, 82 insertions(+), 77 deletions(-) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java index 18a80dc16..3ee0d9d3e 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java @@ -9,7 +9,7 @@ import com.iluwatar.cqrs.domain.model.Book; import com.iluwatar.cqrs.util.HibernateUtil; /** - * This class is implementation of {@link ICommandService} interface. It uses Hibernate as an api for persistence. + * This class is an implementation of {@link ICommandService} interface. It uses Hibernate as an api for persistence. * */ public class CommandServiceImpl implements ICommandService { @@ -17,99 +17,99 @@ public class CommandServiceImpl implements ICommandService { private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); private Author getAuthorByUsername(String username) { - Session session = sessionFactory.openSession(); - Query query = session.createQuery("from Author where username=:username"); - query.setParameter("username", username); - Author author = (Author) query.uniqueResult(); - session.close(); + Author author = null; + try (Session session = sessionFactory.openSession()) { + Query query = session.createQuery("from Author where username=:username"); + query.setParameter("username", username); + author = (Author) query.uniqueResult(); + } return author; } private Book getBookByTitle(String title) { - Session session = sessionFactory.openSession(); - Query query = session.createQuery("from Book where title=:title"); - query.setParameter("title", title); - Book book = (Book) query.uniqueResult(); - session.close(); + Book book = null; + try (Session session = sessionFactory.openSession()) { + Query query = session.createQuery("from Book where title=:title"); + query.setParameter("title", title); + book = (Book) query.uniqueResult(); + } return book; } @Override public void authorCreated(String username, String name, String email) { Author author = new Author(username, name, email); - Session session = sessionFactory.openSession(); - session.beginTransaction(); - session.save(author); - session.getTransaction().commit(); - session.close(); + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.save(author); + session.getTransaction().commit(); + } } @Override public void bookAddedToAuthor(String title, double price, String username) { Author author = getAuthorByUsername(username); Book book = new Book(title, price, author); - Session session = sessionFactory.openSession(); - session.beginTransaction(); - session.save(book); - session.getTransaction().commit(); - session.close(); + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.save(book); + session.getTransaction().commit(); + } } @Override public void authorNameUpdated(String username, String name) { Author author = getAuthorByUsername(username); author.setName(name); - Session session = sessionFactory.openSession(); - session.beginTransaction(); - session.update(author); - session.getTransaction().commit(); - session.close(); + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.update(author); + session.getTransaction().commit(); + } } @Override public void authorUsernameUpdated(String oldUsername, String newUsername) { Author author = getAuthorByUsername(oldUsername); author.setUsername(newUsername); - Session session = sessionFactory.openSession(); - session.beginTransaction(); - session.update(author); - session.getTransaction().commit(); - session.close(); - + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.update(author); + session.getTransaction().commit(); + } } @Override public void authorEmailUpdated(String username, String email) { Author author = getAuthorByUsername(username); author.setEmail(email); - Session session = sessionFactory.openSession(); - session.beginTransaction(); - session.update(author); - session.getTransaction().commit(); - session.close(); - + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.update(author); + session.getTransaction().commit(); + } } @Override public void bookTitleUpdated(String oldTitle, String newTitle) { Book book = getBookByTitle(oldTitle); book.setTitle(newTitle); - Session session = sessionFactory.openSession(); - session.beginTransaction(); - session.update(book); - session.getTransaction().commit(); - session.close(); + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.update(book); + session.getTransaction().commit(); + } } @Override public void bookPriceUpdated(String title, double price) { Book book = getBookByTitle(title); book.setPrice(price); - Session session = sessionFactory.openSession(); - session.beginTransaction(); - session.update(book); - session.getTransaction().commit(); - session.close(); + try (Session session = sessionFactory.openSession()) { + session.beginTransaction(); + session.update(book); + session.getTransaction().commit(); + } } } diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java index 55a40c277..f3a616d59 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java @@ -23,55 +23,60 @@ public class QueryServiceImpl implements IQueryService { @Override public Author getAuthorByUsername(String username) { - Session session = sessionFactory.openSession(); - SQLQuery sqlQuery = session - .createSQLQuery("SELECT a.username as \"username\", a.name as \"name\", a.email as \"email\"" - + "FROM Author a where a.username=:username"); - sqlQuery.setParameter("username", username); - Author authorDTo = (Author) sqlQuery.setResultTransformer(Transformers.aliasToBean(Author.class)).uniqueResult(); - session.close(); + Author authorDTo = null; + try (Session session = sessionFactory.openSession()) { + SQLQuery sqlQuery = session + .createSQLQuery("SELECT a.username as \"username\", a.name as \"name\", a.email as \"email\"" + + "FROM Author a where a.username=:username"); + sqlQuery.setParameter("username", username); + authorDTo = (Author) sqlQuery.setResultTransformer(Transformers.aliasToBean(Author.class)).uniqueResult(); + } return authorDTo; } @Override public Book getBook(String title) { - Session session = sessionFactory.openSession(); - SQLQuery sqlQuery = session - .createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + " FROM Book b where b.title=:title"); - sqlQuery.setParameter("title", title); - Book bookDTo = (Book) sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).uniqueResult(); - session.close(); + Book bookDTo = null; + try (Session session = sessionFactory.openSession()) { + SQLQuery sqlQuery = session + .createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + " FROM Book b where b.title=:title"); + sqlQuery.setParameter("title", title); + bookDTo = (Book) sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).uniqueResult(); + } return bookDTo; } @Override public List getAuthorBooks(String username) { - Session session = sessionFactory.openSession(); - SQLQuery sqlQuery = session.createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" - + " FROM Author a , Book b where b.author_id = a.id and a.username=:username"); - sqlQuery.setParameter("username", username); - List bookDTos = sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).list(); - session.close(); + List bookDTos = null; + try (Session session = sessionFactory.openSession()) { + SQLQuery sqlQuery = session.createSQLQuery("SELECT b.title as \"title\", b.price as \"price\"" + + " FROM Author a , Book b where b.author_id = a.id and a.username=:username"); + sqlQuery.setParameter("username", username); + bookDTos = sqlQuery.setResultTransformer(Transformers.aliasToBean(Book.class)).list(); + } return bookDTos; } @Override public BigInteger getAuthorBooksCount(String username) { - Session session = sessionFactory.openSession(); - SQLQuery sqlQuery = session.createSQLQuery( - "SELECT count(b.title)" + " FROM Book b, Author a where b.author_id = a.id and a.username=:username"); - sqlQuery.setParameter("username", username); - BigInteger bookcount = (BigInteger) sqlQuery.uniqueResult(); - session.close(); + BigInteger bookcount = null; + try (Session session = sessionFactory.openSession()) { + SQLQuery sqlQuery = session.createSQLQuery( + "SELECT count(b.title)" + " FROM Book b, Author a where b.author_id = a.id and a.username=:username"); + sqlQuery.setParameter("username", username); + bookcount = (BigInteger) sqlQuery.uniqueResult(); + } return bookcount; } @Override public BigInteger getAuthorsCount() { - Session session = sessionFactory.openSession(); - SQLQuery sqlQuery = session.createSQLQuery("SELECT count(id) from Author"); - BigInteger authorcount = (BigInteger) sqlQuery.uniqueResult(); - session.close(); + BigInteger authorcount = null; + try (Session session = sessionFactory.openSession()) { + SQLQuery sqlQuery = session.createSQLQuery("SELECT count(id) from Author"); + authorcount = (BigInteger) sqlQuery.uniqueResult(); + } return authorcount; } From a221245909376b34b6468516ba31e4d612175398 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 29 Jul 2017 12:14:15 +0100 Subject: [PATCH 306/492] Use Logger instead of println --- .../main/java/com/iluwatar/cqrs/app/App.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java index 02c4bed3c..497b0f499 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java @@ -25,6 +25,9 @@ package com.iluwatar.cqrs.app; import java.math.BigInteger; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.iluwatar.cqrs.commandes.CommandServiceImpl; import com.iluwatar.cqrs.commandes.ICommandService; import com.iluwatar.cqrs.dto.Author; @@ -39,6 +42,8 @@ import com.iluwatar.cqrs.util.HibernateUtil; * */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * @@ -71,12 +76,12 @@ public class App { Book dddBook = queries.getBook("Domain-Driven Design"); List jBlochBooks = queries.getAuthorBooks("jBloch"); - System.out.println("Author username : " + nullAuthor); - System.out.println("Author eEvans : " + eEvans); - System.out.println("jBloch number of books : " + jBlochBooksCount); - System.out.println("Number of authors : " + authorsCount); - System.out.println("DDD book : " + dddBook); - System.out.println("jBloch books : " + jBlochBooks); + LOGGER.info("Author username : {}", nullAuthor); + LOGGER.info("Author eEvans : {}", eEvans); + LOGGER.info("jBloch number of books : {}", jBlochBooksCount); + LOGGER.info("Number of authors : {}", authorsCount); + LOGGER.info("DDD book : {}", dddBook); + LOGGER.info("jBloch books : {}", jBlochBooks); HibernateUtil.getSessionFactory().close(); } From c572fe885ed87a4079fbce0b90abab2a5f9f2867 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 29 Jul 2017 12:16:19 +0100 Subject: [PATCH 307/492] add check on null objects --- .../com/iluwatar/cqrs/commandes/CommandServiceImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java index 3ee0d9d3e..f1c88a925 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java @@ -23,6 +23,9 @@ public class CommandServiceImpl implements ICommandService { query.setParameter("username", username); author = (Author) query.uniqueResult(); } + if (author == null) { + throw new NullPointerException("Author " + username + " doesn't exist!"); + } return author; } @@ -33,6 +36,9 @@ public class CommandServiceImpl implements ICommandService { query.setParameter("title", title); book = (Book) query.uniqueResult(); } + if (book == null) { + throw new NullPointerException("Book " + title + " doesn't exist!"); + } return book; } From 7ae9e3ee223330be90d31b04cee922d56c52cec8 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 29 Jul 2017 13:13:08 +0100 Subject: [PATCH 308/492] add a description of the pattern --- cqrs/src/main/java/com/iluwatar/cqrs/app/App.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java index 497b0f499..a943a7f88 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java @@ -38,7 +38,13 @@ import com.iluwatar.cqrs.util.HibernateUtil; /** * CQRS : Command Query Responsibility Segregation. A pattern used to separate query services from commands or writes - * services. + * services. The pattern is very simple but it has many consequences. For example, it can be used to tackle down a + * complex domain, or to use other architectures that were hard to implement with the classical way. + * + * This implementation is an example of managing books and authors in a library. The persistence of books and authors is + * done according to the CQRS architecture. A command side that deals with a data model to persist(insert,update,delete) + * objects to a database. And a query side that uses native queries to get data from the database and return objects as + * DTOs (Data transfer Objects). * */ public class App { From 871df4f91893da869715fc7c41b0ac481d04bf36 Mon Sep 17 00:00:00 2001 From: Sabiq Ihab Date: Sat, 29 Jul 2017 13:26:54 +0100 Subject: [PATCH 309/492] close connection before throwing an exception --- .../java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java index f1c88a925..86d9cb10b 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java @@ -24,6 +24,7 @@ public class CommandServiceImpl implements ICommandService { author = (Author) query.uniqueResult(); } if (author == null) { + HibernateUtil.getSessionFactory().close(); throw new NullPointerException("Author " + username + " doesn't exist!"); } return author; @@ -37,6 +38,7 @@ public class CommandServiceImpl implements ICommandService { book = (Book) query.uniqueResult(); } if (book == null) { + HibernateUtil.getSessionFactory().close(); throw new NullPointerException("Book " + title + " doesn't exist!"); } return book; From ffbf56f01af4f86d15a6fe7436320d9ddd20b0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 29 Jul 2017 21:41:11 +0300 Subject: [PATCH 310/492] CQRS pattern: Add missing license headers --- .../cqrs/commandes/CommandServiceImpl.java | 22 +++++++++++++++++ .../cqrs/commandes/ICommandService.java | 22 +++++++++++++++++ .../iluwatar/cqrs/domain/model/Author.java | 22 +++++++++++++++++ .../com/iluwatar/cqrs/domain/model/Book.java | 22 +++++++++++++++++ .../java/com/iluwatar/cqrs/dto/Author.java | 22 +++++++++++++++++ .../main/java/com/iluwatar/cqrs/dto/Book.java | 22 +++++++++++++++++ .../iluwatar/cqrs/queries/IQueryService.java | 22 +++++++++++++++++ .../cqrs/queries/QueryServiceImpl.java | 22 +++++++++++++++++ .../com/iluwatar/cqrs/util/HibernateUtil.java | 22 +++++++++++++++++ cqrs/src/main/resources/hibernate.cfg.xml | 24 +++++++++++++++++++ cqrs/src/main/resources/logback.xml | 24 +++++++++++++++++++ .../com/iluwatar/cqrs/IntegrationTest.java | 22 +++++++++++++++++ cqrs/src/test/resources/hibernate.cfg.xml | 24 +++++++++++++++++++ cqrs/src/test/resources/logback.xml | 24 +++++++++++++++++++ 14 files changed, 316 insertions(+) diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java index 86d9cb10b..a15f8a457 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.commandes; import org.hibernate.Query; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java index eb3cc43a1..1da3f6c42 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/commandes/ICommandService.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.commandes; /** diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java index 308fb4f5d..1d110cb59 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.domain.model; import javax.persistence.Entity; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java index 3d14fae47..8d9ba0ca3 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.domain.model; import javax.persistence.Entity; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java index b7a7ae880..34d082e86 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.dto; import java.util.Objects; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java index b3f0f62d3..ff4d258af 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.dto; import java.util.Objects; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java index 3e3d6ab10..9c0252b0a 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/IQueryService.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.queries; import java.math.BigInteger; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java index f3a616d59..dc44d0f1b 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.queries; import java.math.BigInteger; diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java b/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java index c8f41762e..a5b59e20d 100644 --- a/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java +++ b/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs.util; import org.hibernate.SessionFactory; diff --git a/cqrs/src/main/resources/hibernate.cfg.xml b/cqrs/src/main/resources/hibernate.cfg.xml index 151983337..4ea142166 100644 --- a/cqrs/src/main/resources/hibernate.cfg.xml +++ b/cqrs/src/main/resources/hibernate.cfg.xml @@ -1,4 +1,28 @@ + diff --git a/cqrs/src/main/resources/logback.xml b/cqrs/src/main/resources/logback.xml index 6b5d24345..e9694c41c 100644 --- a/cqrs/src/main/resources/logback.xml +++ b/cqrs/src/main/resources/logback.xml @@ -1,4 +1,28 @@ + diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java b/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java index c9e3b36f4..dd10f658d 100644 --- a/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java +++ b/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.cqrs; import static org.junit.Assert.assertEquals; diff --git a/cqrs/src/test/resources/hibernate.cfg.xml b/cqrs/src/test/resources/hibernate.cfg.xml index 151983337..4ea142166 100644 --- a/cqrs/src/test/resources/hibernate.cfg.xml +++ b/cqrs/src/test/resources/hibernate.cfg.xml @@ -1,4 +1,28 @@ + diff --git a/cqrs/src/test/resources/logback.xml b/cqrs/src/test/resources/logback.xml index 6b5d24345..e9694c41c 100644 --- a/cqrs/src/test/resources/logback.xml +++ b/cqrs/src/test/resources/logback.xml @@ -1,4 +1,28 @@ + From 0271e55983a27fd73ebe00a7ab87dac3b00ed611 Mon Sep 17 00:00:00 2001 From: "mahendran.mookkiah" Date: Sat, 5 Aug 2017 10:07:28 -0400 Subject: [PATCH 311/492] #587 SonarQube reports bugs --- .../model/view/presenter/FileLoader.java | 18 +++++++++++++++--- .../view/presenter/FileSelectorPresenter.java | 9 ++++++++- .../model/view/presenter/FileSelectorView.java | 4 +++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java index 01af677ae..f5606e638 100644 --- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java +++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java @@ -25,6 +25,10 @@ package com.iluwatar.model.view.presenter; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; +import java.io.Serializable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Every instance of this class represents the Model component in the Model-View-Presenter @@ -32,7 +36,14 @@ import java.io.FileReader; *

    * It is responsible for reading and loading the contents of a given file. */ -public class FileLoader { +public class FileLoader implements Serializable{ + + /** + * Generated serial version UID + */ + private static final long serialVersionUID = -4745803872902019069L; + + private static final Logger LOGGER = LoggerFactory.getLogger(FileLoader.class); /** * Indicates if the file is loaded or not. @@ -48,7 +59,8 @@ public class FileLoader { * Loads the data of the file specified. */ public String loadData() { - try (BufferedReader br = new BufferedReader(new FileReader(new File(this.fileName)))) { + String dataFileName = this.fileName; + try (BufferedReader br = new BufferedReader(new FileReader(new File(dataFileName)))) { StringBuilder sb = new StringBuilder(); String line; @@ -60,7 +72,7 @@ public class FileLoader { return sb.toString(); } catch (Exception e) { - e.printStackTrace(); + LOGGER.error("File {} does not exist", dataFileName); } return null; diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java index f2fefe8eb..560a8d274 100644 --- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java +++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java @@ -22,13 +22,20 @@ */ package com.iluwatar.model.view.presenter; +import java.io.Serializable; + /** * Every instance of this class represents the Presenter component in the Model-View-Presenter * architectural pattern. *

    * It is responsible for reacting to the user's actions and update the View component. */ -public class FileSelectorPresenter { +public class FileSelectorPresenter implements Serializable{ + + /** + * Generated serial version UID + */ + private static final long serialVersionUID = 1210314339075855074L; /** * The View component that the presenter interacts with. diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java index cfafadbab..5272ea0b7 100644 --- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java +++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java @@ -22,11 +22,13 @@ */ package com.iluwatar.model.view.presenter; +import java.io.Serializable; + /** * This interface represents the View component in the Model-View-Presenter pattern. It can be * implemented by either the GUI components, or by the Stub. */ -public interface FileSelectorView { +public interface FileSelectorView extends Serializable{ /** * Opens the view. From 9f612ecfdac6c14e3580f477458f9c3f1c7498bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20Hamzao=C4=9Fullar=C4=B1?= Date: Sat, 5 Aug 2017 23:33:08 +0300 Subject: [PATCH 312/492] first commit --- event-sourcing/README.md | 21 ++++++++++++++++++ event-sourcing/etc/.gitkeep | 0 event-sourcing/pom.xml | 43 +++++++++++++++++++++++++++++++++++++ event-sourcing/src/.gitkeep | 0 4 files changed, 64 insertions(+) create mode 100644 event-sourcing/README.md create mode 100644 event-sourcing/etc/.gitkeep create mode 100644 event-sourcing/pom.xml create mode 100644 event-sourcing/src/.gitkeep diff --git a/event-sourcing/README.md b/event-sourcing/README.md new file mode 100644 index 000000000..c513d2da9 --- /dev/null +++ b/event-sourcing/README.md @@ -0,0 +1,21 @@ +--- +layout: pattern +title: Event Sourcing +folder: event-sourcing +permalink: /patterns/event-sourcing/ +categories: Concurrency +tags: + - Java + - Difficulty Intermediate + - Performance +--- + +## Intent + +## Applicability +Use the Event Sourcing pattern when + +* You have a limited accesibility resource and the asynchronous process is acceptable to reach that + +## Credits + diff --git a/event-sourcing/etc/.gitkeep b/event-sourcing/etc/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml new file mode 100644 index 000000000..6dc90063e --- /dev/null +++ b/event-sourcing/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + java-design-patterns + com.iluwatar + 1.17.0-SNAPSHOT + + event-sourcing + + + junit + junit + test + + + \ No newline at end of file diff --git a/event-sourcing/src/.gitkeep b/event-sourcing/src/.gitkeep new file mode 100644 index 000000000..e69de29bb From 1474a50e5e612af12372979af2c62f1da5db9bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20Hamzao=C4=9Fullar=C4=B1?= Date: Sun, 6 Aug 2017 22:51:43 +0300 Subject: [PATCH 313/492] Example done with app class --- event-sourcing/pom.xml | 7 ++ .../event/sourcing/api/DomainEvent.java | 41 ++++++++ .../event/sourcing/api/EventProcessor.java | 11 +++ .../sourcing/api/ExternalEventListener.java | 8 ++ .../event/sourcing/api/ProcessorJournal.java | 10 ++ .../com/iluwatar/event/sourcing/app/App.java | 58 +++++++++++ .../event/sourcing/domain/Account.java | 63 ++++++++++++ .../event/sourcing/domain/Transaction.java | 46 +++++++++ .../sourcing/event/AccountCreateEvent.java | 43 ++++++++ .../sourcing/event/MoneyDepositEvent.java | 38 +++++++ .../sourcing/event/MoneyTransferEvent.java | 56 +++++++++++ .../sourcing/event/MoneyWithdrawalEvent.java | 38 +++++++ .../gateway/AccountCreateContractSender.java | 12 +++ .../event/sourcing/gateway/Gateways.java | 17 ++++ .../sourcing/gateway/TransactionLogger.java | 12 +++ .../sourcing/journal/JsonFileJournal.java | 99 +++++++++++++++++++ .../processor/DomainEventProcessor.java | 48 +++++++++ .../sourcing/service/AccountService.java | 22 +++++ .../service/MoneyTransactionService.java | 35 +++++++ .../sourcing/service/SequenceIdGenerator.java | 14 +++ .../sourcing/state/AccountAggregate.java | 29 ++++++ pom.xml | 1 + 22 files changed, 708 insertions(+) create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java create mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml index 6dc90063e..35d462cb1 100644 --- a/event-sourcing/pom.xml +++ b/event-sourcing/pom.xml @@ -39,5 +39,12 @@ junit test + + + com.google.code.gson + gson + 2.8.1 + + \ No newline at end of file diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java new file mode 100644 index 000000000..d77654869 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java @@ -0,0 +1,41 @@ +package com.iluwatar.event.sourcing.api; + +import java.io.Serializable; + +/** + * Created by serdarh on 06.08.2017. + */ +public abstract class DomainEvent implements Serializable { + private final long sequenceId; + private final long createdTime; + private boolean replica = false; + private final String eventClassName; + + public DomainEvent(long sequenceId, long createdTime, String eventClassName) { + this.sequenceId = sequenceId; + this.createdTime = createdTime; + this.eventClassName = eventClassName; + } + + public long getSequenceId() { + return sequenceId; + } + + public long getCreatedTime() { + return createdTime; + } + + public boolean isReplica() { + return replica; + } + + public void setReplica(boolean replica) { + this.replica = replica; + } + + public abstract void process(); + + public String getEventClassName() { + return eventClassName; + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java new file mode 100644 index 000000000..729efc83c --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java @@ -0,0 +1,11 @@ +package com.iluwatar.event.sourcing.api; + +/** + * Created by serdarh on 06.08.2017. + */ +public interface EventProcessor { + void process(DomainEvent domainEvent); + void setPrecessorJournal(ProcessorJournal precessorJournal); + void addExternalEventListener(ExternalEventListener externalEventListener); + void recover(); +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java new file mode 100644 index 000000000..a1cb78108 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java @@ -0,0 +1,8 @@ +package com.iluwatar.event.sourcing.api; + +/** + * Created by serdarh on 06.08.2017. + */ +public interface ExternalEventListener { + void notify(DomainEvent domainEvent); +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java new file mode 100644 index 000000000..906c66247 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java @@ -0,0 +1,10 @@ +package com.iluwatar.event.sourcing.api; + +/** + * Created by serdarh on 06.08.2017. + */ +public interface ProcessorJournal { + void write(DomainEvent domainEvent); + void reset(); + DomainEvent readNext(); +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java new file mode 100644 index 000000000..8627736f1 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java @@ -0,0 +1,58 @@ +package com.iluwatar.event.sourcing.app; + +import com.iluwatar.event.sourcing.journal.JsonFileJournal; +import com.iluwatar.event.sourcing.processor.DomainEventProcessor; +import com.iluwatar.event.sourcing.service.AccountService; +import com.iluwatar.event.sourcing.service.MoneyTransactionService; +import com.iluwatar.event.sourcing.state.AccountAggregate; + +import java.math.BigDecimal; + +/** + * Created by serdarh on 06.08.2017. + */ +public class App { + + public static void main(String[] args) { + System.out.println("Running the system first time............"); + + DomainEventProcessor domainEventProcessor = new DomainEventProcessor(); + JsonFileJournal jsonFileJournal = new JsonFileJournal(); + jsonFileJournal.reset(); + domainEventProcessor.setPrecessorJournal(jsonFileJournal); + + System.out.println("Creating th accounts............"); + + AccountService accountService = new AccountService(domainEventProcessor); + MoneyTransactionService moneyTransactionService = new MoneyTransactionService(domainEventProcessor); + accountService.createAccount(1,"Daenerys Targaryen"); + accountService.createAccount(2,"Jon Snow"); + + System.out.println("Do some money operations............"); + + moneyTransactionService.depositMoney(1,new BigDecimal("100000")); + moneyTransactionService.depositMoney(2,new BigDecimal("10")); + + moneyTransactionService.transferMoney(1,2,new BigDecimal("10000")); + moneyTransactionService.withdrawalMoney(2, new BigDecimal("1000")); + + System.out.println("...............State:............"); + System.out.println(AccountAggregate.getAccount(1)); + System.out.println(AccountAggregate.getAccount(2)); + + System.out.println("At that point system goes down state in memory cleared............"); + + AccountAggregate.resetState(); + + System.out.println("Recover the syste by the events in journal file............"); + + domainEventProcessor = new DomainEventProcessor(); + jsonFileJournal = new JsonFileJournal(); + domainEventProcessor.setPrecessorJournal(jsonFileJournal); + domainEventProcessor.recover(); + + System.out.println("...............State Recovered:............"); + System.out.println(AccountAggregate.getAccount(1)); + System.out.println(AccountAggregate.getAccount(2)); + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java new file mode 100644 index 000000000..5a7a77fcf --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java @@ -0,0 +1,63 @@ +package com.iluwatar.event.sourcing.domain; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by serdarh on 06.08.2017. + */ +public class Account { + private final int accountNo; + private final String owner; + private BigDecimal money; + private List transactions; + + public Account(int accountNo, String owner) { + this.accountNo = accountNo; + this.owner = owner; + money = BigDecimal.ZERO; + transactions = new ArrayList<>(); + } + + public int getAccountNo() { + return accountNo; + } + + public String getOwner() { + return owner; + } + + public BigDecimal getMoney() { + return money; + } + + public List getTransactions() { + return transactions; + } + + public void setMoney(BigDecimal money) { + this.money = money; + } + + public void setTransactions(List transactions) { + this.transactions = transactions; + } + + public Account copy() { + Account account = new Account(accountNo, owner); + account.setMoney(money); + account.setTransactions(transactions); + return account; + } + + @Override + public String toString() { + return "Account{" + + "accountNo=" + accountNo + + ", owner='" + owner + '\'' + + ", money=" + money + + ", transactions=" + transactions + + '}'; + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java new file mode 100644 index 000000000..557efbedc --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java @@ -0,0 +1,46 @@ +package com.iluwatar.event.sourcing.domain; + +import java.math.BigDecimal; + +/** + * Created by serdarh on 06.08.2017. + */ +public class Transaction { + private final int accountNo; + private final BigDecimal moneyIn; + private final BigDecimal moneyOut; + private final BigDecimal lastBalance; + + public Transaction(int accountNo, BigDecimal moneyIn, BigDecimal moneyOut, BigDecimal lastBalance) { + this.accountNo = accountNo; + this.moneyIn = moneyIn; + this.moneyOut = moneyOut; + this.lastBalance = lastBalance; + } + + public int getAccountNo() { + return accountNo; + } + + public BigDecimal getMoneyIn() { + return moneyIn; + } + + public BigDecimal getMoneyOut() { + return moneyOut; + } + + public BigDecimal getLastBalance() { + return lastBalance; + } + + @Override + public String toString() { + return "Transaction{" + + "accountNo=" + accountNo + + ", moneyIn=" + moneyIn + + ", moneyOut=" + moneyOut + + ", lastBalance=" + lastBalance + + '}'; + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java new file mode 100644 index 000000000..3957a4fe7 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java @@ -0,0 +1,43 @@ +package com.iluwatar.event.sourcing.event; + +import com.iluwatar.event.sourcing.api.DomainEvent; +import com.iluwatar.event.sourcing.domain.Account; +import com.iluwatar.event.sourcing.gateway.Gateways; +import com.iluwatar.event.sourcing.state.AccountAggregate; + +/** + * Created by serdarh on 06.08.2017. + */ +public class AccountCreateEvent extends DomainEvent { + private final int accountNo; + private final String owner; + + public AccountCreateEvent(long sequenceId, long createdTime, int accountNo, String owner) { + super(sequenceId, createdTime, "AccountCreateEvent"); + this.accountNo = accountNo; + this.owner = owner; + } + + public int getAccountNo() { + return accountNo; + } + + public String getOwner() { + return owner; + } + + @Override + public void process() { + Account account = AccountAggregate.getAccount(accountNo); + if(account!=null){ + throw new RuntimeException("Account already exists"); + } + account = new Account(accountNo,owner); + AccountAggregate.putAccount(account); + + // check if this event is replicated from journal before calling an external gateway function + if(!isReplica()) { + Gateways.getAccountCreateContractSender().sendContractInfo(account); + } + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java new file mode 100644 index 000000000..ffa9d0763 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java @@ -0,0 +1,38 @@ +package com.iluwatar.event.sourcing.event; + +import com.iluwatar.event.sourcing.api.DomainEvent; +import com.iluwatar.event.sourcing.domain.Account; +import com.iluwatar.event.sourcing.domain.Transaction; +import com.iluwatar.event.sourcing.gateway.Gateways; +import com.iluwatar.event.sourcing.state.AccountAggregate; + +import java.math.BigDecimal; + +/** + * Created by serdarh on 06.08.2017. + */ +public class MoneyDepositEvent extends DomainEvent { + private BigDecimal money; + private int accountNo; + + public MoneyDepositEvent(long sequenceId, long createdTime, int accountNo,BigDecimal money) { + super(sequenceId, createdTime, "MoneyDepositEvent"); + this.money = money; + this.accountNo = accountNo; + } + + @Override + public void process() { + Account account = AccountAggregate.getAccount(accountNo); + if(account==null){ + throw new RuntimeException("Account not found"); + } + account.setMoney(account.getMoney().add(money)); + Transaction transaction = new Transaction(accountNo,money,BigDecimal.ZERO,account.getMoney()); + account.getTransactions().add(transaction); + AccountAggregate.putAccount(account); + if(!isReplica()) { + Gateways.getTransactionLogger().log(transaction); + } + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java new file mode 100644 index 000000000..4e0fb9829 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java @@ -0,0 +1,56 @@ +package com.iluwatar.event.sourcing.event; + +import com.iluwatar.event.sourcing.api.DomainEvent; +import com.iluwatar.event.sourcing.domain.Account; +import com.iluwatar.event.sourcing.domain.Transaction; +import com.iluwatar.event.sourcing.gateway.Gateways; +import com.iluwatar.event.sourcing.state.AccountAggregate; + +import java.math.BigDecimal; + +/** + * Created by serdarh on 06.08.2017. + */ +public class MoneyTransferEvent extends DomainEvent { + private BigDecimal money; + private int accountNoFrom; + private int accountNoTo; + + public MoneyTransferEvent(long sequenceId, long createdTime, BigDecimal money, int accountNoFrom, int accountNoTo) { + super(sequenceId, createdTime, "MoneyTransferEvent"); + this.money = money; + this.accountNoFrom = accountNoFrom; + this.accountNoTo = accountNoTo; + } + + @Override + public void process() { + Account accountFrom = AccountAggregate.getAccount(accountNoFrom); + if(accountFrom==null){ + throw new RuntimeException("Account not found "+accountNoFrom); + } + Account accountTo = AccountAggregate.getAccount(accountNoTo); + if(accountTo==null){ + throw new RuntimeException("Account not found"+ accountTo); + } + if(accountFrom.getMoney().compareTo(money)==-1){ + throw new RuntimeException("Insufficient Account Balance"); + } + accountFrom.setMoney(accountFrom.getMoney().subtract(money)); + accountTo.setMoney(accountTo.getMoney().add(money)); + + Transaction transactionFrom = new Transaction(accountNoFrom,BigDecimal.ZERO,money,accountFrom.getMoney()); + accountFrom.getTransactions().add(transactionFrom); + + Transaction transactionTo = new Transaction(accountNoTo,money,BigDecimal.ZERO,accountTo.getMoney()); + accountTo.getTransactions().add(transactionTo); + + AccountAggregate.putAccount(accountFrom); + AccountAggregate.putAccount(accountTo); + + if(!isReplica()) { + Gateways.getTransactionLogger().log(transactionFrom); + Gateways.getTransactionLogger().log(transactionTo); + } + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java new file mode 100644 index 000000000..27a63d13d --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java @@ -0,0 +1,38 @@ +package com.iluwatar.event.sourcing.event; + +import com.iluwatar.event.sourcing.api.DomainEvent; +import com.iluwatar.event.sourcing.domain.Account; +import com.iluwatar.event.sourcing.domain.Transaction; +import com.iluwatar.event.sourcing.gateway.Gateways; +import com.iluwatar.event.sourcing.state.AccountAggregate; + +import java.math.BigDecimal; + +/** + * Created by serdarh on 06.08.2017. + */ +public class MoneyWithdrawalEvent extends DomainEvent { + private BigDecimal money; + private int accountNo; + + public MoneyWithdrawalEvent(long sequenceId, long createdTime, int accountNo,BigDecimal money) { + super(sequenceId, createdTime, "MoneyWithdrawalEvent"); + this.money = money; + this.accountNo = accountNo; + } + + @Override + public void process() { + Account account = AccountAggregate.getAccount(accountNo); + if(account==null){ + throw new RuntimeException("Account not found"); + } + account.setMoney(account.getMoney().subtract(money)); + Transaction transaction = new Transaction(accountNo,BigDecimal.ZERO,money,account.getMoney()); + account.getTransactions().add(transaction); + AccountAggregate.putAccount(account); + if(!isReplica()) { + Gateways.getTransactionLogger().log(transaction); + } + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java new file mode 100644 index 000000000..42dfccf7b --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java @@ -0,0 +1,12 @@ +package com.iluwatar.event.sourcing.gateway; + +import com.iluwatar.event.sourcing.domain.Account; + +/** + * Created by serdarh on 06.08.2017. + */ +public class AccountCreateContractSender { + public void sendContractInfo(Account account){ + // an example imaginary funciton which sends account info to some external end point + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java new file mode 100644 index 000000000..d167393bf --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java @@ -0,0 +1,17 @@ +package com.iluwatar.event.sourcing.gateway; + +/** + * Created by serdarh on 06.08.2017. + */ +public class Gateways { + private static AccountCreateContractSender accountCreateContractSender = new AccountCreateContractSender(); + private static TransactionLogger transactionLogger = new TransactionLogger(); + + public static AccountCreateContractSender getAccountCreateContractSender() { + return accountCreateContractSender; + } + + public static TransactionLogger getTransactionLogger() { + return transactionLogger; + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java new file mode 100644 index 000000000..6d961d96e --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java @@ -0,0 +1,12 @@ +package com.iluwatar.event.sourcing.gateway; + +import com.iluwatar.event.sourcing.domain.Transaction; + +/** + * Created by serdarh on 06.08.2017. + */ +public class TransactionLogger { + public void log(Transaction transaction) { + // example imaginary function that logs the transaction to somewhere + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java new file mode 100644 index 000000000..45a982c19 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java @@ -0,0 +1,99 @@ +package com.iluwatar.event.sourcing.journal; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.iluwatar.event.sourcing.api.DomainEvent; +import com.iluwatar.event.sourcing.api.ProcessorJournal; +import com.iluwatar.event.sourcing.event.AccountCreateEvent; +import com.iluwatar.event.sourcing.event.MoneyDepositEvent; +import com.iluwatar.event.sourcing.event.MoneyTransferEvent; +import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by serdarh on 06.08.2017. + */ +public class JsonFileJournal implements ProcessorJournal{ + + private File aFile; + private List events = new ArrayList<>(); + private int index = 0; + public JsonFileJournal() { + aFile = new File("Journal.json"); + if(aFile.exists()) { + try (BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(aFile), "UTF-8"))) { + String line; + while ((line = input.readLine()) != null) { + events.add(line); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }else{ + reset(); + } + } + + @Override + public void write(DomainEvent domainEvent) { + Gson gson = new Gson(); + JsonElement jsonElement; + if(domainEvent instanceof AccountCreateEvent) { + jsonElement = gson.toJsonTree(domainEvent, AccountCreateEvent.class); + }else if(domainEvent instanceof MoneyDepositEvent) { + jsonElement = gson.toJsonTree(domainEvent, MoneyDepositEvent.class); + }else if(domainEvent instanceof MoneyWithdrawalEvent) { + jsonElement = gson.toJsonTree(domainEvent, MoneyWithdrawalEvent.class); + }else if(domainEvent instanceof MoneyTransferEvent) { + jsonElement = gson.toJsonTree(domainEvent, MoneyTransferEvent.class); + }else{ + throw new RuntimeException("Journal Event not recegnized"); + } + + try (Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aFile, true), "UTF-8"))) { + String eventString = jsonElement.toString(); + output.write(eventString +"\r\n"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void reset() { + aFile.delete(); + } + + + @Override + public DomainEvent readNext() { + if(index>=events.size()){ + return null; + } + String event = events.get(index); + index++; + + JsonParser parser = new JsonParser(); + JsonElement jsonElement = parser.parse(event); + String eventClassName = jsonElement.getAsJsonObject().get("eventClassName").getAsString(); + Gson gson = new Gson(); + DomainEvent domainEvent; + if(eventClassName.equals("AccountCreateEvent")) { + domainEvent = gson.fromJson(jsonElement, AccountCreateEvent.class); + }else if(eventClassName.equals("MoneyDepositEvent")) { + domainEvent = gson.fromJson(jsonElement, MoneyDepositEvent.class); + }else if(eventClassName.equals("MoneyTransferEvent")) { + domainEvent = gson.fromJson(jsonElement, MoneyTransferEvent.class); + }else if(eventClassName.equals("MoneyWithdrawalEvent")) { + domainEvent = gson.fromJson(jsonElement, MoneyWithdrawalEvent.class); + }else{ + throw new RuntimeException("Journal Event not recegnized"); + } + + domainEvent.setReplica(true); + return domainEvent; + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java new file mode 100644 index 000000000..a23c41905 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java @@ -0,0 +1,48 @@ +package com.iluwatar.event.sourcing.processor; + +import com.iluwatar.event.sourcing.api.DomainEvent; +import com.iluwatar.event.sourcing.api.EventProcessor; +import com.iluwatar.event.sourcing.api.ExternalEventListener; +import com.iluwatar.event.sourcing.api.ProcessorJournal; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by serdarh on 06.08.2017. + */ +public class DomainEventProcessor implements EventProcessor { + + private ProcessorJournal precessorJournal; + private List externalEventListeners = new ArrayList<>(); + + @Override + public void process(DomainEvent domainEvent) { + externalEventListeners.forEach(externalEventListener -> externalEventListener.notify(domainEvent)); + domainEvent.process(); + precessorJournal.write(domainEvent); + } + + @Override + public void setPrecessorJournal(ProcessorJournal precessorJournal) { + this.precessorJournal = precessorJournal; + } + + @Override + public void addExternalEventListener(ExternalEventListener externalEventListener) { + externalEventListeners.add(externalEventListener); + } + + @Override + public void recover() { + DomainEvent domainEvent; + while(true) { + domainEvent = precessorJournal.readNext(); + if(domainEvent==null){ + break; + }else{ + domainEvent.process(); + } + } + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java new file mode 100644 index 000000000..b0a707788 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java @@ -0,0 +1,22 @@ +package com.iluwatar.event.sourcing.service; + +import com.iluwatar.event.sourcing.api.EventProcessor; +import com.iluwatar.event.sourcing.event.AccountCreateEvent; + +import java.util.Date; + +/** + * Created by serdarh on 06.08.2017. + */ +public class AccountService { + private EventProcessor eventProcessor; + + public AccountService(EventProcessor eventProcessor) { + this.eventProcessor = eventProcessor; + } + + public void createAccount(int accountNo, String owner){ + AccountCreateEvent accountCreateEvent = new AccountCreateEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(),accountNo,owner); + eventProcessor.process(accountCreateEvent); + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java new file mode 100644 index 000000000..80c2a5a4f --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java @@ -0,0 +1,35 @@ +package com.iluwatar.event.sourcing.service; + +import com.iluwatar.event.sourcing.api.EventProcessor; +import com.iluwatar.event.sourcing.event.MoneyDepositEvent; +import com.iluwatar.event.sourcing.event.MoneyTransferEvent; +import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * Created by serdarh on 06.08.2017. + */ +public class MoneyTransactionService { + private EventProcessor eventProcessor; + + public MoneyTransactionService(EventProcessor eventProcessor) { + this.eventProcessor = eventProcessor; + } + + public void depositMoney(int accountNo, BigDecimal money){ + MoneyDepositEvent moneyDepositEvent = new MoneyDepositEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money); + eventProcessor.process(moneyDepositEvent); + } + + public void withdrawalMoney(int accountNo, BigDecimal money){ + MoneyWithdrawalEvent moneyWithdrawalEvent = new MoneyWithdrawalEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money); + eventProcessor.process(moneyWithdrawalEvent); + } + + public void transferMoney(int accountNoFrom, int accountNoTo, BigDecimal money){ + MoneyTransferEvent moneyTransferEvent = new MoneyTransferEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), money, accountNoFrom, accountNoTo); + eventProcessor.process(moneyTransferEvent); + } +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java new file mode 100644 index 000000000..2eec6a70d --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java @@ -0,0 +1,14 @@ +package com.iluwatar.event.sourcing.service; + +/** + * Created by serdarh on 06.08.2017. + */ +public class SequenceIdGenerator { + private static long sequenceId = 0L; + + public static long nextSequenceId(){ + sequenceId++; + return sequenceId; + } + +} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java new file mode 100644 index 000000000..b927af0e1 --- /dev/null +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java @@ -0,0 +1,29 @@ +package com.iluwatar.event.sourcing.state; + +import com.iluwatar.event.sourcing.domain.Account; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by serdarh on 06.08.2017. + */ +public class AccountAggregate { + private static Map accounts = new HashMap<>(); + + public static void putAccount(Account account){ + accounts.put(account.getAccountNo(), account); + } + + public static Account getAccount(int accountNo){ + Account account = accounts.get(accountNo); + if(account == null){ + return null; + } + return account.copy(); + } + + public static void resetState(){ + accounts = new HashMap<>(); + } +} diff --git a/pom.xml b/pom.xml index 4f4b5dee6..5f46c9401 100644 --- a/pom.xml +++ b/pom.xml @@ -143,6 +143,7 @@ extension-objects marker cqrs + event-sourcing From db10b937f2b07e8357ebb0b4eb02ca0972d83b25 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Wed, 9 Aug 2017 15:27:36 +0530 Subject: [PATCH 314/492] #348 - Data Tranfer Object : Added module to project. --- data-bus/pom.xml | 4 ++++ data-transfer-object/pom.xml | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 data-transfer-object/pom.xml diff --git a/data-bus/pom.xml b/data-bus/pom.xml index a77b59106..22b3f0229 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -27,6 +27,10 @@ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 + pom + + ../data-transfer-object + 1.16.14 diff --git a/data-transfer-object/pom.xml b/data-transfer-object/pom.xml new file mode 100644 index 000000000..c5bfc7fa8 --- /dev/null +++ b/data-transfer-object/pom.xml @@ -0,0 +1,16 @@ + + + + data-bus + com.iluwatar + 1.17.0-SNAPSHOT + ../data-bus/pom.xml + + 4.0.0 + + data-transfer-object + + + \ No newline at end of file From 67d4477d25698e08e8fd6fcf0ccf82de484a7304 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Thu, 10 Aug 2017 13:45:46 +0530 Subject: [PATCH 315/492] #348 - Data Tranfer Object : Add puml file to etc. --- data-transfer-object/etc/data-transfer-object.urm.puml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data-transfer-object/etc/data-transfer-object.urm.puml diff --git a/data-transfer-object/etc/data-transfer-object.urm.puml b/data-transfer-object/etc/data-transfer-object.urm.puml new file mode 100644 index 000000000..02af47ddf --- /dev/null +++ b/data-transfer-object/etc/data-transfer-object.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file From 148de06bb1f07efc91f745198762444ef7cf55ba Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Fri, 11 Aug 2017 15:42:21 +0530 Subject: [PATCH 316/492] #348 - Data Tranfer Object : Implement Data Transfer Object pattern simple version. --- .../iluwatar/datatransfer/CustomerDto.java | 60 ++++++++++++++ .../datatransfer/CustomerResource.java | 63 +++++++++++++++ .../datatransfer/CustomerResourceTest.java | 81 +++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java create mode 100644 data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java create mode 100644 data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java new file mode 100644 index 000000000..ce9ffdb78 --- /dev/null +++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Gopinath Langote + * + * 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.datatransfer; + +/** + * {@link CustomerDto} is a data transfer object POJO. Instead of sending individual information to client + * We can send related information together in POJO. + *

    + * Dto will not have any business logic in it. + */ +public class CustomerDto { + private String id; + private String firstName; + private String lastName; + + /** + * @param id customer id + * @param firstName customer first name + * @param lastName customer last name + */ + public CustomerDto(String id, String firstName, String lastName) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + } + + public String getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } +} diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java new file mode 100644 index 000000000..a4926d08c --- /dev/null +++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Gopinath Langote + * + * 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.datatransfer; + +import java.util.List; + +/** + * The resource class which serves customer information. + * This class act as server in the demo. Which has all customer details. + */ +public class CustomerResource { + private List customers; + + /** + * @param customers initialize resource with existing customers. Act as database. + */ + public CustomerResource(List customers) { + this.customers = customers; + } + + /** + * @return : all customers in list. + */ + public List getAllCustomers() { + return customers; + } + + /** + * @param customer save new customer to list. + */ + public void save(CustomerDto customer) { + customers.add(customer); + } + + /** + * @param customerId delete customer with id {@code customerId} + */ + public void delete(String customerId) { + customers.removeIf(customer -> customer.getId().equals(customerId)); + } +} \ No newline at end of file diff --git a/data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java new file mode 100644 index 000000000..8d5c7b50f --- /dev/null +++ b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java @@ -0,0 +1,81 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Gopinath Langote + * + * 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.datatransfer; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * tests {@link CustomerResource}. + */ +public class CustomerResourceTest { + @Test + public void shouldGetAllCustomers() { + CustomerDto customer = new CustomerDto("1", "David", "Roy"); + List customers = new ArrayList<>(); + customers.add(customer); + + CustomerResource customerResource = new CustomerResource(customers); + + List allCustomers = customerResource.getAllCustomers(); + + assertEquals(allCustomers.size(), 1); + assertEquals(allCustomers.get(0).getId(), "1"); + assertEquals(allCustomers.get(0).getFirstName(), "David"); + assertEquals(allCustomers.get(0).getLastName(), "Roy"); + } + + @Test + public void shouldSaveCustomer() { + CustomerDto customer = new CustomerDto("1", "David", "Roy"); + CustomerResource customerResource = new CustomerResource(new ArrayList<>()); + + customerResource.save(customer); + + List allCustomers = customerResource.getAllCustomers(); + assertEquals(allCustomers.get(0).getId(), "1"); + assertEquals(allCustomers.get(0).getFirstName(), "David"); + assertEquals(allCustomers.get(0).getLastName(), "Roy"); + } + + @Test + public void shouldDeleteCustomer() { + CustomerDto customer = new CustomerDto("1", "David", "Roy"); + List customers = new ArrayList<>(); + customers.add(customer); + + CustomerResource customerResource = new CustomerResource(customers); + + customerResource.delete(customer.getId()); + + List allCustomers = customerResource.getAllCustomers(); + assertEquals(allCustomers.size(), 0); + } + +} \ No newline at end of file From 229fda9f3c0530e5a26380b77a12b86b702dd11b Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Fri, 11 Aug 2017 15:55:12 +0530 Subject: [PATCH 317/492] #348 - Data Tranfer Object : Add puml diagram. --- .../etc/data-transfer-object.urm.png | Bin 0 -> 14193 bytes .../etc/data-transfer-object.urm.puml | 19 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 data-transfer-object/etc/data-transfer-object.urm.png diff --git a/data-transfer-object/etc/data-transfer-object.urm.png b/data-transfer-object/etc/data-transfer-object.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..3c4377ee978dc37ff69d045d771583790062b8ea GIT binary patch literal 14193 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 + + CustomerResource(customers : List) + + delete(customerId : String) + + getAllCustomers() : List + + save(customer : CustomerDto) + } +} +CustomerResource --> "-customers" CustomerDto @enduml \ No newline at end of file From df9be7850490558e7e506961a24c4816765c37d4 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Fri, 11 Aug 2017 16:17:51 +0530 Subject: [PATCH 318/492] #348 - Data Tranfer Object : customer client request customer details to server at one shot. --- .../etc/data-transfer-object.urm.png | Bin 14193 -> 19132 bytes .../etc/data-transfer-object.urm.puml | 5 ++ .../datatransfer/CustomerClientApp.java | 78 ++++++++++++++++++ .../datatransfer/CustomerResourceTest.java | 14 ++-- 4 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java diff --git a/data-transfer-object/etc/data-transfer-object.urm.png b/data-transfer-object/etc/data-transfer-object.urm.png index 3c4377ee978dc37ff69d045d771583790062b8ea..46facff8dee4c45b2c6bbafb7ea6c3b6be80dfc3 100644 GIT binary patch literal 19132 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 R(&9dol~j_*6aUNm{{y~+`I`U$ literal 14193 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 {static} + } class CustomerDto { - firstName : String - id : String diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java new file mode 100644 index 000000000..3a9e8b88f --- /dev/null +++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java @@ -0,0 +1,78 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Gopinath Langote + * + * 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.datatransfer; + +import java.util.ArrayList; +import java.util.List; + +/** + * The Data Transfer Object pattern is a design pattern in which an data transfer object is used to serve related + * information together to avoid multiple call for each piece of information. + *

    + * In this example, ({@link CustomerClientApp}) as as customer details consumer i.e. client to request for + * customer details to server. + *

    + * CustomerResource ({@link CustomerResource}) act as server to serve customer information. + * And The CustomerDto ({@link CustomerDto} is data transfer object to share customer information. + */ +public class CustomerClientApp { + /** + * Method as act client and request to server for details. + * + * @param args program argument. + */ + public static void main(String[] args) { + List customers = new ArrayList<>(); + CustomerDto customerOne = new CustomerDto("1", "Kelly", "Brown"); + CustomerDto customerTwo = new CustomerDto("2", "Alfonso", "Bass"); + customers.add(customerOne); + customers.add(customerTwo); + + CustomerResource customerResource = new CustomerResource(customers); + + System.out.println("All customers:-"); + List allCustomers = customerResource.getAllCustomers(); + printCustomerDetails(allCustomers); + + System.out.println("----------------------------------------------------------"); + + System.out.println("Deleting customer with id {1}"); + customerResource.delete(customerOne.getId()); + allCustomers = customerResource.getAllCustomers(); + printCustomerDetails(allCustomers); + + System.out.println("----------------------------------------------------------"); + + System.out.println("Adding customer three}"); + CustomerDto customerThree = new CustomerDto("3", "Lynda", "Blair"); + customerResource.save(customerThree); + allCustomers = customerResource.getAllCustomers(); + printCustomerDetails(allCustomers); + } + + private static void printCustomerDetails(List allCustomers) { + allCustomers.forEach(customer -> System.out.println(customer.getFirstName())); + } +} diff --git a/data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java index 8d5c7b50f..adfe66b7d 100644 --- a/data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java +++ b/data-transfer-object/src/test/java/com/iluwatar/datatransfer/CustomerResourceTest.java @@ -37,7 +37,7 @@ import static org.junit.Assert.assertEquals; public class CustomerResourceTest { @Test public void shouldGetAllCustomers() { - CustomerDto customer = new CustomerDto("1", "David", "Roy"); + CustomerDto customer = new CustomerDto("1", "Melody", "Yates"); List customers = new ArrayList<>(); customers.add(customer); @@ -47,26 +47,26 @@ public class CustomerResourceTest { assertEquals(allCustomers.size(), 1); assertEquals(allCustomers.get(0).getId(), "1"); - assertEquals(allCustomers.get(0).getFirstName(), "David"); - assertEquals(allCustomers.get(0).getLastName(), "Roy"); + assertEquals(allCustomers.get(0).getFirstName(), "Melody"); + assertEquals(allCustomers.get(0).getLastName(), "Yates"); } @Test public void shouldSaveCustomer() { - CustomerDto customer = new CustomerDto("1", "David", "Roy"); + CustomerDto customer = new CustomerDto("1", "Rita", "Reynolds"); CustomerResource customerResource = new CustomerResource(new ArrayList<>()); customerResource.save(customer); List allCustomers = customerResource.getAllCustomers(); assertEquals(allCustomers.get(0).getId(), "1"); - assertEquals(allCustomers.get(0).getFirstName(), "David"); - assertEquals(allCustomers.get(0).getLastName(), "Roy"); + assertEquals(allCustomers.get(0).getFirstName(), "Rita"); + assertEquals(allCustomers.get(0).getLastName(), "Reynolds"); } @Test public void shouldDeleteCustomer() { - CustomerDto customer = new CustomerDto("1", "David", "Roy"); + CustomerDto customer = new CustomerDto("1", "Terry", "Nguyen"); List customers = new ArrayList<>(); customers.add(customer); From bfbc8fd740f74739017cd95008a16146e5484217 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Fri, 11 Aug 2017 16:51:46 +0530 Subject: [PATCH 319/492] #348 - Data Tranfer Object : Add readme.md --- data-transfer-object/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 data-transfer-object/README.md diff --git a/data-transfer-object/README.md b/data-transfer-object/README.md new file mode 100644 index 000000000..ad9b9f4e2 --- /dev/null +++ b/data-transfer-object/README.md @@ -0,0 +1,30 @@ +--- +layout: pattern +title: Data Transfer Object +folder: data-transfer-object +permalink: /patterns/data-transfer-object/ +categories: Architectural +tags: + - Java + - KISS + - YAGNI + - Difficulty-Beginner +--- + +## Intent +Pass data with multiple attributes in one shot from client to server, +to avoid multiple calls to remote server. + +![alt text](./etc/data-transfer-object.urm.png "data-transfer-object") + +## Applicability +Use the Data Transfer Object pattern when + +* The client is asking for multiple information. And the information is related. +* When you want to boost the performance to get resources. +* You want reduced number of remote calls. + +## Credits + +* [Design Pattern - Transfer Object Pattern](https://www.tutorialspoint.com/design_pattern/transfer_object_pattern.htm) +* [Data Transfer Object](https://msdn.microsoft.com/en-us/library/ff649585.aspx) From 64824d65aa9df0928d67e31bc7e2e0290c989ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20Hamzao=C4=9Fullar=C4=B1?= Date: Sat, 12 Aug 2017 16:21:35 +0300 Subject: [PATCH 320/492] Some Object Orianted refactor --- .../event/sourcing/api/DomainEvent.java | 10 +-- .../event/sourcing/api/EventProcessor.java | 1 - .../sourcing/api/ExternalEventListener.java | 8 --- .../event/sourcing/domain/Account.java | 67 +++++++++++++++++++ .../sourcing/event/AccountCreateEvent.java | 8 +-- .../sourcing/event/MoneyDepositEvent.java | 18 ++--- .../sourcing/event/MoneyTransferEvent.java | 34 ++++------ .../sourcing/event/MoneyWithdrawalEvent.java | 18 ++--- .../sourcing/journal/JsonFileJournal.java | 2 +- .../processor/DomainEventProcessor.java | 11 --- 10 files changed, 106 insertions(+), 71 deletions(-) delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java index d77654869..e20d03232 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java @@ -8,7 +8,7 @@ import java.io.Serializable; public abstract class DomainEvent implements Serializable { private final long sequenceId; private final long createdTime; - private boolean replica = false; + private boolean realTime = true; private final String eventClassName; public DomainEvent(long sequenceId, long createdTime, String eventClassName) { @@ -25,12 +25,12 @@ public abstract class DomainEvent implements Serializable { return createdTime; } - public boolean isReplica() { - return replica; + public boolean isRealTime() { + return realTime; } - public void setReplica(boolean replica) { - this.replica = replica; + public void setRealTime(boolean realTime) { + this.realTime = realTime; } public abstract void process(); diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java index 729efc83c..0fc673bf4 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java @@ -6,6 +6,5 @@ package com.iluwatar.event.sourcing.api; public interface EventProcessor { void process(DomainEvent domainEvent); void setPrecessorJournal(ProcessorJournal precessorJournal); - void addExternalEventListener(ExternalEventListener externalEventListener); void recover(); } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java deleted file mode 100644 index a1cb78108..000000000 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ExternalEventListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.iluwatar.event.sourcing.api; - -/** - * Created by serdarh on 06.08.2017. - */ -public interface ExternalEventListener { - void notify(DomainEvent domainEvent); -} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java index 5a7a77fcf..48cda1eca 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java @@ -1,5 +1,12 @@ package com.iluwatar.event.sourcing.domain; +import com.iluwatar.event.sourcing.event.AccountCreateEvent; +import com.iluwatar.event.sourcing.event.MoneyDepositEvent; +import com.iluwatar.event.sourcing.event.MoneyTransferEvent; +import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent; +import com.iluwatar.event.sourcing.gateway.Gateways; +import com.iluwatar.event.sourcing.state.AccountAggregate; + import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -60,4 +67,64 @@ public class Account { ", transactions=" + transactions + '}'; } + + private Transaction depositMoney(BigDecimal money) { + this.money = this.money.add(money); + Transaction transaction = new Transaction(accountNo,money,BigDecimal.ZERO,this.money); + transactions.add(transaction); + return transaction; + } + + private Transaction withdrawMoney(BigDecimal money) { + this.money = this.money.subtract(money); + Transaction transaction = new Transaction(accountNo,BigDecimal.ZERO,money,this.money); + transactions.add(transaction); + return transaction; + } + + private void handleDeposit(BigDecimal money,boolean realTime) { + Transaction transaction = depositMoney(money); + AccountAggregate.putAccount(this); + if(realTime) { + Gateways.getTransactionLogger().log(transaction); + } + } + + private void handleWithdrawal(BigDecimal money, boolean realTime) { + if(this.money.compareTo(money)==-1){ + throw new RuntimeException("Insufficient Account Balance"); + } + + Transaction transaction = withdrawMoney(money); + AccountAggregate.putAccount(this); + if(realTime) { + Gateways.getTransactionLogger().log(transaction); + } + } + + public void handleEvent(MoneyDepositEvent moneyDepositEvent) { + handleDeposit(moneyDepositEvent.getMoney(),moneyDepositEvent.isRealTime()); + } + + + public void handleEvent(MoneyWithdrawalEvent moneyWithdrawalEvent) { + handleWithdrawal(moneyWithdrawalEvent.getMoney(),moneyWithdrawalEvent.isRealTime()); + } + + + public void handleTransferFromEvent(MoneyTransferEvent moneyTransferEvent) { + handleWithdrawal(moneyTransferEvent.getMoney(),moneyTransferEvent.isRealTime()); + } + + public void handleTransferToEvent(MoneyTransferEvent moneyTransferEvent) { + handleDeposit(moneyTransferEvent.getMoney(),moneyTransferEvent.isRealTime()); + } + + public void handleEvent(AccountCreateEvent accountCreateEvent) { + AccountAggregate.putAccount(this); + // check if this event is replicated from journal before calling an external gateway function + if(accountCreateEvent.isRealTime()) { + Gateways.getAccountCreateContractSender().sendContractInfo(this); + } + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java index 3957a4fe7..1ea089e2f 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java @@ -2,7 +2,6 @@ package com.iluwatar.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; -import com.iluwatar.event.sourcing.gateway.Gateways; import com.iluwatar.event.sourcing.state.AccountAggregate; /** @@ -33,11 +32,6 @@ public class AccountCreateEvent extends DomainEvent { throw new RuntimeException("Account already exists"); } account = new Account(accountNo,owner); - AccountAggregate.putAccount(account); - - // check if this event is replicated from journal before calling an external gateway function - if(!isReplica()) { - Gateways.getAccountCreateContractSender().sendContractInfo(account); - } + account.handleEvent(this); } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java index ffa9d0763..384a9e198 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java @@ -2,8 +2,6 @@ package com.iluwatar.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; -import com.iluwatar.event.sourcing.domain.Transaction; -import com.iluwatar.event.sourcing.gateway.Gateways; import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; @@ -21,18 +19,20 @@ public class MoneyDepositEvent extends DomainEvent { this.accountNo = accountNo; } + public BigDecimal getMoney() { + return money; + } + + public int getAccountNo() { + return accountNo; + } + @Override public void process() { Account account = AccountAggregate.getAccount(accountNo); if(account==null){ throw new RuntimeException("Account not found"); } - account.setMoney(account.getMoney().add(money)); - Transaction transaction = new Transaction(accountNo,money,BigDecimal.ZERO,account.getMoney()); - account.getTransactions().add(transaction); - AccountAggregate.putAccount(account); - if(!isReplica()) { - Gateways.getTransactionLogger().log(transaction); - } + account.handleEvent(this); } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java index 4e0fb9829..6c873d4db 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java @@ -2,8 +2,6 @@ package com.iluwatar.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; -import com.iluwatar.event.sourcing.domain.Transaction; -import com.iluwatar.event.sourcing.gateway.Gateways; import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; @@ -23,6 +21,18 @@ public class MoneyTransferEvent extends DomainEvent { this.accountNoTo = accountNoTo; } + public BigDecimal getMoney() { + return money; + } + + public int getAccountNoFrom() { + return accountNoFrom; + } + + public int getAccountNoTo() { + return accountNoTo; + } + @Override public void process() { Account accountFrom = AccountAggregate.getAccount(accountNoFrom); @@ -33,24 +43,8 @@ public class MoneyTransferEvent extends DomainEvent { if(accountTo==null){ throw new RuntimeException("Account not found"+ accountTo); } - if(accountFrom.getMoney().compareTo(money)==-1){ - throw new RuntimeException("Insufficient Account Balance"); - } - accountFrom.setMoney(accountFrom.getMoney().subtract(money)); - accountTo.setMoney(accountTo.getMoney().add(money)); - Transaction transactionFrom = new Transaction(accountNoFrom,BigDecimal.ZERO,money,accountFrom.getMoney()); - accountFrom.getTransactions().add(transactionFrom); - - Transaction transactionTo = new Transaction(accountNoTo,money,BigDecimal.ZERO,accountTo.getMoney()); - accountTo.getTransactions().add(transactionTo); - - AccountAggregate.putAccount(accountFrom); - AccountAggregate.putAccount(accountTo); - - if(!isReplica()) { - Gateways.getTransactionLogger().log(transactionFrom); - Gateways.getTransactionLogger().log(transactionTo); - } + accountFrom.handleTransferFromEvent(this); + accountTo.handleTransferToEvent(this); } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java index 27a63d13d..8ed617008 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java @@ -2,8 +2,6 @@ package com.iluwatar.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; -import com.iluwatar.event.sourcing.domain.Transaction; -import com.iluwatar.event.sourcing.gateway.Gateways; import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; @@ -21,18 +19,20 @@ public class MoneyWithdrawalEvent extends DomainEvent { this.accountNo = accountNo; } + public BigDecimal getMoney() { + return money; + } + + public int getAccountNo() { + return accountNo; + } + @Override public void process() { Account account = AccountAggregate.getAccount(accountNo); if(account==null){ throw new RuntimeException("Account not found"); } - account.setMoney(account.getMoney().subtract(money)); - Transaction transaction = new Transaction(accountNo,BigDecimal.ZERO,money,account.getMoney()); - account.getTransactions().add(transaction); - AccountAggregate.putAccount(account); - if(!isReplica()) { - Gateways.getTransactionLogger().log(transaction); - } + account.handleEvent(this); } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java index 45a982c19..2d50db55f 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java @@ -93,7 +93,7 @@ public class JsonFileJournal implements ProcessorJournal{ throw new RuntimeException("Journal Event not recegnized"); } - domainEvent.setReplica(true); + domainEvent.setRealTime(false); return domainEvent; } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java index a23c41905..55453b1c6 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java @@ -2,23 +2,17 @@ package com.iluwatar.event.sourcing.processor; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.api.EventProcessor; -import com.iluwatar.event.sourcing.api.ExternalEventListener; import com.iluwatar.event.sourcing.api.ProcessorJournal; -import java.util.ArrayList; -import java.util.List; - /** * Created by serdarh on 06.08.2017. */ public class DomainEventProcessor implements EventProcessor { private ProcessorJournal precessorJournal; - private List externalEventListeners = new ArrayList<>(); @Override public void process(DomainEvent domainEvent) { - externalEventListeners.forEach(externalEventListener -> externalEventListener.notify(domainEvent)); domainEvent.process(); precessorJournal.write(domainEvent); } @@ -28,11 +22,6 @@ public class DomainEventProcessor implements EventProcessor { this.precessorJournal = precessorJournal; } - @Override - public void addExternalEventListener(ExternalEventListener externalEventListener) { - externalEventListeners.add(externalEventListener); - } - @Override public void recover() { DomainEvent domainEvent; From 746e452c2bfbb623df0285a53793cf791f3539f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 12 Aug 2017 18:20:45 +0300 Subject: [PATCH 321/492] #590 Add new presentation for Singleton --- singleton/README.md | 29 ++++++++- singleton/etc/singleton.png | Bin 22292 -> 0 bytes singleton/etc/singleton.ucls | 104 ------------------------------- singleton/etc/singleton.urm.puml | 43 ------------- singleton/etc/singleton_1.png | Bin 16417 -> 0 bytes 5 files changed, 27 insertions(+), 149 deletions(-) delete mode 100644 singleton/etc/singleton.png delete mode 100644 singleton/etc/singleton.ucls delete mode 100644 singleton/etc/singleton.urm.puml delete mode 100644 singleton/etc/singleton_1.png diff --git a/singleton/README.md b/singleton/README.md index 4032ffaed..0a81ba0fc 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -15,7 +15,32 @@ tags: Ensure a class only has one instance, and provide a global point of access to it. -![alt text](./etc/singleton_1.png "Singleton") + +## Explanation +Real world example +> There can only be one ivory tower where the wizards study their magic. The same enchanted ivory tower is always used by the wizards. Ivory tower here is singleton. + +In plain words +> Ensures that only one object of a particular class is ever created. + +Wikipedia says +> In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. + +**Programmatic Example** + +Joshua Bloch, Effective Java 2nd Edition p.18 +> A single-element enum type is the best way to implement a singleton +``` +public enum EnumIvoryTower { + INSTANCE; +} +``` +Then in order to use +``` +EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE; +EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE; +assertEquals(enumIvoryTower1, enumIvoryTower2); // true +``` ## Applicability Use the Singleton pattern when @@ -40,7 +65,7 @@ Use the Singleton pattern when * Violates Single Responsibility Principle (SRP) by controlling their own creation and lifecycle. * Encourages using a global shared instance which prevents an object and resources used by this object from being deallocated. -* Creates tightly coupled code that is difficult to test. +* Creates tightly coupled code. The clients of the Singleton become difficult to test. * Makes it almost impossible to subclass a Singleton. ## Credits diff --git a/singleton/etc/singleton.png b/singleton/etc/singleton.png deleted file mode 100644 index 0bf0c9b283b751a3b32179e3e7bd3e2927ff49db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22292 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

    WR8<5D*{^GczS48yE-=>C)RQClp=7 zov}X|P|9jI6}phh2Re|g=evBWTF@Euv~$EX&J?BFe(?q3$U=p~ALVSi?b@>bDH8EA z4r|y@{YFwbsQTq~HwJF@UE3wo!!ItRPS5b$ng&?KlIKLvvTJ#T$tE{IGbq#hOOb{C zc4X)>YsevJ$kYB(t>?N8_I8(-)XD=VK3$s#9erCH+VGYfg)gYSdNYJSCJsZJkhC~X zw>X?8nqZTTOK%uxaxsdIyNEBQZ$s3|i8a99qh~vWLa@Fb)%INA)fu3^{O@%Jj;5fo z&*@5KQ6};o-MIF9S|@2C#vvP=$35Psm}lJ55^IQKq5~QV^2&6^U!kS9wHj6 zA_DsYzrSGNcTe3VN{+`$|C3ryFQpq}FqbyL$rZ@B?DKxgHr!8GZ-hRZm@Ny=^R1Me z8N;4|R(N(DrAC-vR|agMuWB%?mDk>y?VRbV+_L^>qcVYu9a|XK5z_d*s@^If!Lr7iLl&NFc0n+DUcLE}c9v8;gH9yqyIJQ__ zKW};zu~^pAEqx6kHhxLv%qhe@;V(&JTpL{oUkSVMO{NLY)kee1MxN)%b6tYva7Yc3 zLj`%t7}i=LWUk+lXb9dyo$t*W;852Sq(Z-R3|}>JI~V4678$0y&ib8zQY8OMS*KoZ(ZC&OUh7U_U>uI ztf#5;(H(_dj){b*kDHpuJjXEF7(qYj2?U;eS*NoZj<)jnnAkjCU1z9{z_?yF;btKP!#o!n%OvR6rEud_>1CWuBM#G8y;=0+ zW4gR^sEy)?`n^+lhD+KGJnTV5AOX<|U7dGR^RyemHh7*zi5Pn9WQ5t$!`*L`#;*o+ z-B@_+*0?p#)vlHNTK+a$9q!Bq>g@K4iG?_cb}&leqLZOD9-En}y2V!hl1BV;m7;o- zNKmRO>ds}GWY<}mk^o6Tf0BB2khZHa%G4}7w3)Y!#}}3iwRDUib+0Z&;zR(9aBiT~ zhU7nLjn({k7Us^=g8vMle~)soZcLv2M%bqhaGNCqM;IT%z8S!MMYCT;ffZtvE8v%F z?u8(jef|oo9i#I>117xh|5@;8C`!U}F1>5zyrAvNU8oz)nD6Rt@o;-;@r4ajndDOo z^}4b|{Kp!_aEU^a6bqIw*Xotr7=nmL-K{Puuq0PQ(@Jyg#&M(a;)7y-*2N{|q~9+V zypx&%70=FSF#%VK6xW(;DuUlQEd)hdDIS4t<>)PAdL~ZD;Y~*HFw`QTxX;{7u$W0s zG0%=#+4cxJ`h;&kB7)oDHM|5NgP}eWVN;;!RMHHS@aDM0n(% z(+SxwO4-{-$&$}KK_%zoC4SJ{=W~Op#@iAD`|*(U+6bxcp)8Q6Ca=Fb} zj3K3pm=K^8k4_jnFl${qL7(J7uhcEm=BiGUS? zhH#kIj=a`Amt`!ou$q(d4*Um#o2w&g?XLTN(~^CMjC!x(Yr=0k7(0xw-CB=%=3t^0 zy^~Ts9<@(ura34RmQ}~9BfW|C4w*_tbosK`v7K{7IURlue=bq&C_ze;gx1QpylCLu zh|zTJtM2z>&^1pP(^At4B*E6pDryexhP;6z$OZV=&`lXiH*fnA7O<5OqAtx)L2n_$1WC)P2igZTeO-r;JL4qErWf5AP&NO#tl$@>Y z;05h0NO|Fn - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/singleton/etc/singleton.urm.puml b/singleton/etc/singleton.urm.puml deleted file mode 100644 index f61377e17..000000000 --- a/singleton/etc/singleton.urm.puml +++ /dev/null @@ -1,43 +0,0 @@ -@startuml -package com.iluwatar.singleton { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - enum EnumIvoryTower { - + INSTANCE {static} - + toString() : String - + valueOf(name : String) : EnumIvoryTower {static} - + values() : EnumIvoryTower[] {static} - } - class InitializingOnDemandHolderIdiom { - - InitializingOnDemandHolderIdiom() - + getInstance() : InitializingOnDemandHolderIdiom {static} - } - -class HelperHolder { - - INSTANCE : InitializingOnDemandHolderIdiom {static} - - HelperHolder() - } - class IvoryTower { - - INSTANCE : IvoryTower {static} - - IvoryTower() - + getInstance() : IvoryTower {static} - } - class ThreadSafeDoubleCheckLocking { - - instance : ThreadSafeDoubleCheckLocking {static} - - ThreadSafeDoubleCheckLocking() - + getInstance() : ThreadSafeDoubleCheckLocking {static} - } - class ThreadSafeLazyLoadedIvoryTower { - - instance : ThreadSafeLazyLoadedIvoryTower {static} - - ThreadSafeLazyLoadedIvoryTower() - + getInstance() : ThreadSafeLazyLoadedIvoryTower {static} - } -} -IvoryTower --> "-INSTANCE" IvoryTower -ThreadSafeDoubleCheckLocking --> "-instance" ThreadSafeDoubleCheckLocking -ThreadSafeLazyLoadedIvoryTower --> "-instance" ThreadSafeLazyLoadedIvoryTower -HelperHolder ..+ InitializingOnDemandHolderIdiom -HelperHolder --> "-INSTANCE" InitializingOnDemandHolderIdiom -@enduml \ No newline at end of file diff --git a/singleton/etc/singleton_1.png b/singleton/etc/singleton_1.png deleted file mode 100644 index 58dc440a9ca9167260bc6b81f7b710213d046e1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16417 zcmeIZWmJ`2+b#^!-M#2WIu|01fD($*-5m>%?iQp|T2d5{lI}&fA|fT-(k;0s_kBOl zyZ0W?*!vyd_{R6^a}53ATI-tEob#OLc^v0)%*Yq23OJaQmZSb@ezaV- z@msDbe5xtMviGQJglgDq>1&J8bgBir)1nOcr;89In(sS&=5r?TV+CAQ?I3!J|AQ!BsG;p7{1U-fkOKt z!%9sdHYo{py6ExSRIbd7Oc6wdxV`hEHR)9=t3F*l5wdIF$QGt0x?4#sEIg;#y2Ys~ z=#O+}ZisAzyQ|0k!NHPaVXpYl_T-4k@Vnc@MEuy5zMpxA&@c~6LLp`hv_osd`T5Pw zDlT2Y!$aprZ=okoidWm=1hkUB;P67rk!^?B3;|~h+_UKxFWiUe8BKI-{cr2v?c|lJ zf4pAoA;|ZvO0Yz03<2qOyoiY;9U{8a!5zK&>cb=>PEg>_z*cAHS3W13{m;&JXDv>* z*;{&`d$aZMiHUdh4q31R-Kj4&bxBDMs-t^YWQ2A<#v6UT-kRdpglsd)d#=2Oy@U#p zq|2Q?g{$Q?S`0l_zEDbw4Y;|C-&T&zf*ChS1o#)oUA`cy5usXbY^3n^e)K$NrzgL_ z-NArU%JZ#rw{?9L---hjE2M=qF=<2Ad3>C-&C?lSb!6!cQRmiTVPfL?r%|R)PYGkA zMo&(9Vq@z@GAMZT&fNU{Q=^pSRiRN)vC6p;!*eZ9Lr}xn=00f%Xm$(@vGegg=xWdt zL5n<@W_9B0UGTqBQ&6C?Xn+*nU6>`w$wNK4h)HR1v8Zg#)v4@~zJ6_cf!PBgmR)hi zgc7KCKdq8I09(cYwhRZ4CVFe;w5G}J6pvbWB$I+l%;M&fqQAxMVY%%O4zLM_hu^ul zRQQgV$NMNWHH*tg)eDRye+D7_60v{Bo*GR+IfI7V4HJELMcgRs*W2djCpPOd zwI(2Vq;C_M&Ad-t5*5WC(9)8nV&p3q$jg&oYgd-A^*Z-NVX&~^jAlKJS5&AC3meD~ zT2M593`PT6ZD25K(io(S7x$c=C`!~?n3Bf>IS=mL``@(OmLka`3{^qoOhX-^yjE@s-uo>^N}w;ko%;_GGdM8?x$Tn)8LEH zrUZi%Mp7pI>u540l<+-;zLCrC{r3kE?Kz_SOpf~JMTog0$9rexlH>gZEv0X|k7NmP zz2xnUFk8`YO@>#K*`pN$2)_~isqQgsmpIwhsAHI({myAHlO18U#OBh@=5@H-ad%s< zbE=hD9U7*TmPou%j*sTWlOV4#`2L~Bg3?+N6XcG5qLX{hZ1QYtcGO-J#(aG6Bjh4l zvYN%$r(v4ON@sU-`g?-N<#CSq(3C~Fo>u!8F{gz#66lL||IhZvgDJWC`ZJp4x?#12 zDw(8ccx@}?+rOIIzkmBCZ({I^l0#mr#*ISN=yiZAC$EBp4NpqNQ zYc*g9g%J~*i#X`E%j4|!yjA#6%>7O>zn-Vibi9t!T~?^ zcWz9(%o}z0_NZZBcW2243^dXEQn`*fIhCWMZR4mmB7(RQ+PrKWem!O?^mq|ZcC@lw ze0y^qJKrisMLuEsEq|cJi&1p{q&w16QnLQ?6em;gy6PdPTEKs@kgfqw>veH zL#civzn1T=Ybstcm&Zwbin_{4QGRX|janJiGTG9ao!)HXIB!0hMbNJ{Nlt>4`SWNn zg~&OhT256;%7ZBuqBF$7txp~`(%p^z;m&2o?Agv>|+{@JGFR8sKmmuvBn!_ z21m6HS(ujCQeh1WS681;;>22L+&|CV3DE5+^?r>pQ?N%zMC(S)kIsOr6+K(?KE?jp zyy;|rdm!5&cR4ROet`8(EIy&?i-Vr)>K7*`3=ir^aJrbs-D-=9KGwMlf#bDlw(8?O zBQVquR5@K~VxVqvC(#pwIl2<|@o5rjuGl%!kd~#2Dio%5C@kO8p=n7Wn=g$dYqs*p zn$?cbCBLAL;qde)lFl#9@{GJ25y!$$q_H1gAx(V^LuL#LBY%rXFZ`+XEgH9V+* z&ct*aVN3FMD%6*iRqsbk^6$M&kyj}Oh!*FGm@D>A!zdoa$aTf{TF7~H3CK|9Bvc=# z*rmunk9`Wg5RZ*LZe{r}9Fa}cSZ|Q;o4w%^LglYA?c&|MF!LhLTJlsJ_k{UMP1EJb z*S>l)vutcJq|y{7UG-<{LwRo;ErPJ4edvf@{W#Njr4|N;02=P=zLuC_`IzYVKPz!H z@!0{QewaI66{KjRX}utYKk=a8MS&8DCgZ=-1j3x-4S5CUH2Lu4YNL zCydNrsB=Ns*%SJ$5QCUrvg#{cLed)NG7K3kSWEJw<^*s-$q=Rujlfed-JRjRpRgl| zmeh1>Asp(gLHJ^H6LF~-}VrxZAMT@WoeNn)^WBDA+syud^t2EGnJ81wleaRwO6$7 zp_V`V@pq61INcvVmI%Y_$m`)ZWWccrIl8?y&~f98Yt(}%EvOZES7`GE*&(en>`;r< zwe#D#!1K!ZI8f^_ho+~i$ej*K1q8HUYgJj6xB|U+>xO$vx%^i!ws=X;O4ix#6Z8;T zKXsC%RUiGoC!GZ=EN`YvRe zmo?p$0+t4mY{T^*-2UOjB7Vk$h)3J@5iZ{ogv6)lY9baA;@7ZEo~!utQ&EU)Wh)YD zgU!>QO@n0v7!lRICFE0soMyUqUpw$Kt7TXcP;q`tezvr*h|1es9!~{l{%%Y%skZPf zy0Gfh$!xI-)_(=D3q0s44KDEvqHJ#dGo-Mq^{b+19i`4?)g-i zPEAvNy?`T@dta_-();0zEEt;|wn(Me>q?i`U)Ip;b8>42GnK8*r17Kg=)i5KAyR{c`Jrm+p8)R^?>;{Uiu& z=wzbNO7c=qmKHu~Bx$FdH_HvGzR)3gvJ{BV*f-S>yCd+#B4(93zeP)`r?qexYIb#& z+HbY6WjauNde%%rvY`a;%v%j89cN`Je3fjJ7KU^v>gn+DP7}p1@=BJQ2us)Ea36-o zhE;NU{l~w|jKqju%S0u+x8(h0Dzj6o-DsLx5u=Ua#PT&tg4#8N9EJK-4wEyst3Xv+`xYwNbR<)!Pagki~|IAI$Enf{wM z{ReQS?XLVRL(F;keQ0Ru;?OlTxhcf)n6G37=yx-m_)?|ZL{_nnCtI@&2K!=XG5tfW4Q}#32jfk z_6@xOBop^}RA=)&xK%JxSkTe_i~mjZ+#GhJ!E7Cul-ck|rnxyMSHde64#xXe>g`dX z7A`|0B;#S}=~g!U!uEQiWPYk8AmBr`fl}m&l{)98tf^^eO3FvM%kRw{9W+@e(?ysY z9#YV$-(w~wvTBDNLFDLY(JO2c65On+-A>c|&lzG$Y;FGZvTQiB?aegsEgz4~V)^HB zJOCJX+XWsPL?t}DDjb2gU+ZQ^tW@vhtpD5AQ(4(a_||%ZE#$@6D^6pYP8UDD+8(Jk~~ss6vT7@*b1rz19A7 z5ABBlX`CLLsxX+n1mJ+Lg;j-;Ga+0|h_^)JMLf=uu_!+7x^)RYE);7=B%Aelud8H3 zFoLL9eWz^?DE=3#1BPq_Z{3k}Oz4>^qfFXYUe2K`1@58$YZip#_{6Jgzh^P_IuaP| zs=7M{QJReH?0RJ`*ok7>@8&xh_69H&0RE?<61c!UpqzT9z~E-%m9Cil#5{(UMe}+Zzmu?4;_Dinh}W9 zRwzY-mY`icL73hr4Sto1_&;-vSN3peJOzwUegts{Gax0el+0<+z*DtR|K=h!3|JA} z?soN-Cc6?j-y~L+^3L0W7o` z|H6a3v6-FBDmvfMv9z3=nrcwZe&n6&YwEnN92^y8WuE6wEo#)Gq+n=3J;7Cq+iz;Lj$k^yb)3URR@F%&t!IqHbwhO{W9 z^v1+!w*(waRW-aMiB03dqa>f0Y4&K8qa53wb?U1=NFUU0uG{N*`?RH55jy{LI)@7< z2Oy2N+ilKfa<5OO#>G-A%e3Kq&KvbVEZu5#2m(Xp{&cB{E?r!#gd6$&Ks+>@gwd}aAf1Ery%s>gn@-RtVIrsdjYu7OZS=#MS#xNa%l=xP*)^K|Z5T?L zgF`i`!798Q(T~Xl5hrS+$q-!Ha9!ww+>&D04{BdLe=52ZI3nsQzt{`s>Nj<#6|Js& zmNF<{hO9Ycq6ZY%&ve6ilV-)qoZmtt|G+dnjm^_+^PZ+CW<1aDAmB4s)V z8Ak8?y?B~hY^IWf4Ye=g=gf~%cF={B``8J7Nhg(&fKdarFsY+io}@OBZzi& zwp;CeN<1&zfA(e>#13Z#_2xt{iV;1Z*AYIsIl}`KQ9o}arxlC1w<^RP${p070i3>g z5sY^(}7TnW;=_IgLJ*O(~1C2TEJR;wOWX+@&9yWf!v8=!O|foYIY!WlgO z9FdZ4(b}9DnZJWAR)FT36*Hh{mAd`Or}F_fr&r$!uF^9owLa_H3?%Xmat1>8T79-! z(AKE82X_L=H(zsECaZEW<94@ zEUo%n0`R-guRx_jpL{(vS|z}2ooteO}wcSt?Kl^p+OI z+4f&(Sz7f*o8Y_AQ4=npu|l6Dx-3Vk|{A|YaW7K&8L@%*_@YHzaP$3)T=?0-)P z9+Wp*k^8$NXm2NA)pM3^mN9ArK3mh`9v?m_Cm-IS<9T3AHi$-c&Dnb`!y3#D) zns5d#m6%m_;#dZ}dgC+H*H`r9t%$_XbPYyB)uM_qMYK+G4E|hM2@L^3C^Cm>YS$ne ztCh&VW=FLRD_VO7oI6%qMaG8j!EVA$sShov`Sd(-;o z=W;A8I=u&h2Lp|g4(qky*PzK#GF$jmJX($MWGr_A58eRGPN7>;|mQQ>cwJ z31WX8H^zk9G$GY9c$i$|i4OaDR?7Vx-JETPrXxm|F=bDY@5Az(2v@NqTg+pE=kD^< z4zl^@cw^t0)9wA<&nmN*WR(?W32f89-wdER2J5r9@MaEJw0WnDT+Oqx2=4uU`h!%R zHaYFnE)2roP2{>I_SQs^c;oL(U_B9@_=t=|-EX970!|rGB;pvoIKI4ch0zB_5P$qQ z9_q1|)!u%$`K-u7;Us)ngwFk6^goIR89rhz8PhPOc55xw^VKzi;-~H*E1FNOazw_^1#^gMxz6*xdY3AQ}o*~_@Q zb7u7wGTpLTFB>0*6}a!ta1!lFm1>s9E2^pr3kj(xDf!Tc$yt6(OiM#^LJ^Ill?*4< z*3)|^Q0;ZRK3T3;Gn^^nlmh@f3rp|(yu@?NHw1H}gt!c9Y<$jQlJQwb~A zA%ZmssUMd@t#|yz0J_E~?=RubHdF;<8GAntXZilJt9339oe9I5xXKcT_^@*Vr z;?{2n6r4*<7qF6vJ2^Q4fGsR5G!&WB74~KsJz{mlM>eHgnyIihY#)!|FvQpf9nBY~ zBqTEO=}K=*v-|Gl>Hv|sx3@QF9}7KvI5avs+S`lj-#6Fj>gMKle0=N`gYfO!H|@-K z>FIfns;aSa+u?L*5p}h-;;%Qqw!0kq!x0CJYv)-)|9<>dtLPw2*x>qOzsqFi_YcCt z!nVnSP{Gn`3!@pL5)tSSYeDB_E^gUah8!-~qnudyHIubQ|7e#Lfz;A9g(of;Bhsb8 ziSr3v^2y=Ivw@67lc+)dHVTE)FviD^^#^hvVW0|r)P{FTe=ovxgqDlo`JCH%qxEZY zI)9?@k6O-5DHG}p3o*0l6Gg{e|Zkx^dLlJ)4`I z$q=$NCngaZ1e~z6i2VHH^W0Hgr}o5kA$mEp)yP*sbg994 zrMEK#jf_)!ab=}zK2GXEWqDD6c^JCrRQ-T1yUj-r2Yd-YKn>bWAp&aJ`wV9C<;*;w$j z@u#2!K$iixFmBIW|*WyGZrBMfuOxM-n9FX@Y9=vSHug->DX$%0wjkc#9^`wenK@M8PU_z z|Ew^Id;1mya_OrNv0-67Akzli{@Ku~FvMU&-_AE@2wY-t$tzi`;aggax$1rhnPXn> zeOydHddDK}$5$pj(HPZozmA+n5<#vipz1yeIR5v5uou1pjlB=$MH7f{7YCA9_xAR3 za&mV3%JcK{lUSdR=1R7^Zj93Uog~n?yq9>!@_-yw^t!jzC(R7secQY*G(=>NX#Ab1 zjubTsJcy*M)J`l}fp&2(2nHkZx{s|tH|O1yLSJ^hlDJ7cOd>5tK>Z2_fFPE=EZg+NK*e%|N4GumGjwKmZOL*?^wiw>&!x`mN zykp)&4Hg*2%c)b{JvF5*+>xdjDtq)9-B_!lcxSpMx@f801me;RV&o$QNvt^LT6u}3 zF*ggcOTccyRN*+*-?5Mm@p?ipBqYSavE3e0rC(s~PyIF>IfI%;0`l@#S$fs7){C_) z64vYFVi1|ks%~<5`RHg&vRztQ7@?Sm*fIP>vHAH7dsh2JI8l9oNwW(P#tsh;$5M-B zWMp{z_(*!6C_YJn!{HKsm&0K3-$lJ=QG~wf<}bR0A1-zxnVGHBSdF!LpW4nfI0pp< z4G!i)o#7zAb#w#*F_4(`2U#pY0q$GlVQc!W-Wo@WRzTCL+YeqK8JIVt?_#Q~C%4MQMMCr`=ri$&)Aj>NoFX z$(QKxIrteE86)s$M{k4WV7yD(t=_e{xwJzALqny8txemyOb}!l9VEM;=^864Dyrtj z#@(r^kSkgQ>5fpOk;?jdD^aVl91Fxj4e+v3_^3QaZF7|-va@v#dUf`VKpHNIq#H4Y zA1?R21*Kwlx&{p+AmEPuRdHo&dV2bflYS#I5(Zij9q-xx!v5~A!3R}pY^}Zhp+Rh2 zC))Qc%*2)H0i7czbkibZS7x8Za$~m zDe37t)xA%__xV=93RP8Ak&=?u)zuvy9)gwNB&fMxzOatZ2F;HjKi>XPDq=TTw%mRL zS}t_zbk~P{v_}4aEI`4Gy75VUCX+iTCIvph7eob1BK4IV{P=;iSv(9lJ!0;E^8bJE z|KXCn(S&knj5E9;+0@V5uZY6^=8oXV6S>N!mYnR)Ev@*b4oMLz2Rt;L^fS10OZY&n zM~<)-dvA)__m`zcmLfh>76!gGSOa_PeS(z{F_y@$t^V44eV9kL&feB>9vLXH3qxsW z3Ax$Sb`HPv501H<6Jh9Jpg=mfnzpCsY#mBpY|qD0PUj`^M_)3VeIg?8JQ#0454qkE z7ZBmJHQS4URuQI>X(=W;y}r8B2BWXioc>%~Aw}|1@|3i~a8E_A=aXyBS3QzQx2v4%)<@x0iM~Sk9_pT7b7)stGnMN#*FfElp z?+3o=`WAv_*5rOu=4fyu8=-k@+1snC1I!BiPQRX&>efD!mUaibsHF5N+BfpVIUJZD zN>P4n{v2~#lsdTB$5%z)BnyfLjj%RR5gVIZU*w3#KJ}Nd7JYAud7E-^cbp9qzzT+3vr;7+6gfYcvL- zAQbt0H6A#&?&WbcNo%u;F3~IZ^zW3wX14TZs*Tv2;JWMG0Q)QQgj=S3)}ys&U~_O% zZOwqx-yO@KF#U5}()#a1FQtQt_J48Q^pB0nbbZn&efep3>)w0=y#VGLWZGk9nSaI< zSnBXbZtE3cPdYakjJNB`dE5MnIOAf z)ZRF44|5?g$KE@4|9YoyXRfpHZ8<&;x1SrQu6n`;$}0czi~xg6*44K@U^=OyAQMS( zkbe@h{k8KM=wsKoW`ZtF^)S$vk})v0sEJoC%+;IC6sYWJM33%#$hfh4EKN<3e+qk? z<3i`ocHgef4BNE;j^i-%#h9mtNBe+8xu;iE`f@ZoHvt!YGxh|uF*koT*91wIlX7JM z6q8u)x2oHd{Qx844M@HqA;99!&JDI`Jv_y6z1MDY5uJ_r!yO@Frn2ZzI$?YZ;;5GQ;8n^P&v zJdIMzO4y40C)=eLmJs(!3?~#DpDRtp8c!LZS;;+OU_j^pR#z@MzB{WYY-btWJ=fS7 zRn8FttRWGL_oq4?X3RWp8SZn^CPLHKDH%|kzGo@E>xv%Z9L_-w%#Vd+#FaFZgZY! z)yw~Cx~wpwO|&C%+F>BXO}NkDsWb|Ge+-jet*^WnadB#v`}1h*9985xqk8Scy}dS% z=9_;D4cg|)O0Y_q5WFjbvC7?nod4BJh6GD`U#9Vt2f}>M_`;|0dk90s9)YPJcNYEdk+Y) z-V->z_kG<|hPF-dPK%Du1~@3rAG1RDa_*?fQ^@Pg_o>iU506{u?PPtmPasjazWfD7gw=VjJa>Xi&f2xM2tKiF}L#k z$WRL+Agp>#cyqF^zz?b3s7YC zn}?+TK?l(t-(v9TUFIEC|Hk2p_{_|YvNC0p?>$B3`m=x@hB?E2HQ7v+8Qw601b;zi zO*NhsX4bbHzxQ)2<@7KTym4H|5PI)cW+atS;>uYuEQ7!Ho` z0y~5Qm_AbP{3WQEHyY+Syg^MN~<;duhV#PJN)Y57r!eO%svJympL}Q{u5dr ztqA3y`y1O3Ze zi=)BBe?XWabTG%~oI7H_gGP2|s!HzQESch;{Lg@{Am2L%5%AI;Xw49tjJ9O-qdf#M@A1v*1|03Pj*yx`JXH`xbGB^}+issS%Z zRI{*S^u_h@S+EfsVXO-Pz*1m2fKAD9iZ^K%BGK}5vRsYxS6l1a>F-%O2*?%jiVK() z-!4^i=NET(%XFbf$2IR@9d9WfPq_{f-{tyeY%Cqxn46=Af}Zi~fV;}S)#TgxU>DU)2l-0f z$wQ2xAbL*Dl^+0F;>vVpNzkjSNb`dfhoWiJeHFzzsYNEBoypm2@H1@PwqA z+1_64Hl!BRy72_X>1qXNKZ%XkZ8`9upLY1TaGP|WA-^;X?v1?j?l-wGGgm7Sj+uqPjkXTw3YvkJOofg z|6vYH5C)dNYgRn$4e$@#Z+}Pd9-$n@>(5`$wVr^PNWFcGd-xLkllQ-{p8oF(t)Hoc%9=LU>eW=b(~eo^9v*!4Ss3Z&XZ-thN_ZgI?%2kO1b*T)7@Z0z zhuQzYHI*>g;!g)iE3JQ)dx8|={7rI$MT$=p|0Y5`#IeOHzxQYB^X2wjK&Gp;-3m>n^>%B}J21r!RbiQTtIdC8u) z*Yeynm%T9r-@cil&@L6p{R6qyyVO`9ot+YyB4Z|^A3tIR2e-s`ES?`a^YNCf0bB36 z<0BW~LI(s+@8{>-TKnmf(u&J6onxHR#Pmkfe*EVa@I32(>+BtBdU`cKD;5MT_vRKG z8a|e_#Kfex`KwHL9~h_2Ip<1@?0{<(8>7~i*V8p+0NQ^d(m0T1`e&K&V~xbK*4SR{ z1Le}VyV`ou_;0r5a%vlulQY`n_T6z_`S{os+|md%P>3xn2ZV1p-N+tTiT)*#<7YUv z-+0WVk>DDNef@}n)h1&Ka5rzi95SZM4fH&1TA*hD*pc1;Iq zLE}3fG4Sy*h>ENBidNc zx2QdPW`1{@yYh9%DIItZL*)gnjr$KL%LV_@l*{4&(v+DX`Jv#jgux&V-?;-`dK!*( zKKI7$WgYJa!9w12bJ>Us*&MwMayZ-J5f|Upp=clhkty!qf`;_&#(;69&H=0Pg#2%v zI2q7m>cTuB(A|fT(mb9DJL(EQHOA8cmqeNx-4>NQ+XJZ>eDpcJz#W)D8pjTV`l%`Q zU_2K>Ts4_5)bF1`IcFuZ#IGEsI(`L8;cpeBI;;-D;D;wRmf*I8HczD_t*AREuD~5A z5#T=0SO&>N(`g^!R-&{f)UXA(`P=AQP|GC#dW*;tHMZ?)M7+%KaPOTM?6Q;x=p%NZA zo^zjpe){Oqj7r8tmvuY1V3Q9E)HY(fb*q`H=ZJD=8V?APAL7whOjgWIaT(L;TpMDQ zvIEYwshJGwM_+Ug8-Ni;^a@ydYVCf@+$*SS3Q#&kkG(my_Uqq2E1chNjODiXRmsI+ zvO{_`qb4?cdn$(qrpxm?;^}h^u%et4Vh{M$lkb3-uf0-v0#3TVuCK4;5;WkpB?4Tq z+8E6~K0l`w_x_TXmseg6TA5Y}Ixk+}larTJR4jb4`QG2JxC#_IG_>HPqs7jUiwjRI zthX6Lc6AQ3XH!*XgV6|A=ldQo7_YD}ji?I~QFd7wCupf^pB)|seI#t^M3H|&9Q*SA zvWtAoHcmSNRw}>5Yqf6#pw0jXJHzg#wa>9-#v)@&vi5Khro2BODqUS&OM%E}Xh4gj zPR|r}aB*=N92jVXEy`bj)jdBAL7*K{mRCIb`LXeAVH;kAtz37>tAx#U(>SO(ZMs$cMzt(urnfB5jB zg?uWH(R`JeLaG-~D3g*Gd27JtiuCFXF>l+x*laf!- z(9q!Hn%mmhEi`*L4J0zRdY{5s-2Yr$e6ju}lb!&yrdIhFN+4uQQ92F*qhFo^5IsMr zX3MC`$UI0Dh00a!J1$AX5ueSsbZJae%E{>JT~tY{caG!ZUQoV3BO*%bjiK_`ojCp6Rd2HB=_Zd*sAU+g25HN#Qpf+TKpF)e3plqCn%fz$lS2G0A%*|6Ur%+^Hi$ zX`OO%f^@)cQF_pmLUOT%)Q{0!U`j9jk@XaF6-A9)=TUoR{n zK*TsWI3WCkRYHiIp>FHpHysqZQew}glEwje=(zXsqF;M)fm)qu;y)?^i4Kl40TdWY&RY2Ts*$E^ehb9*xxD51o>RW3{fyx3z<@CD+F--`*M{^OqJR@unx8lS9?#3Bg*{ji3Wi&g zgj4JoBR-G}u766nme)bbLlg5V$@ksi$Z9CkuP^2UgdlKzg`MW-fCE8PRA(e2Ep)j6 zj?vdZ{q~AE_Ls|}GcL2rNabn%zXa9xe*{%C*u9{-ZufI?&GP>G4Bs7!{NMKx18>5^ zO404Kb?DGk5x;cIG>L)+G2;PlgVBPSlxfSM@YC!U#HIH7dLA4M)?s4 zT9$`>4>ij?&vw!SMGR4-!-!%zmU0Mu7}s|)kMD-FLR8Fe74&=mm}r{Ylu^Ee9rP|P zli+enY5xMGw+h`LEG(i69!^Q|Bm5x^Wx`ZG3r;hgp1zg|J4H*dtq(M=P zcVGn)F9yn4XOGA$7GMZ%clYqX!@w}fjKHNnIy(dTZVx1Apu3_popK;^WWfY=CY-d# zr<^|~6=uD8ZqM+l4%^WhTnp5pycHnA1sl}@@BFnl_pUEF_D{=uIx_jp;RI-`OZ8u3su=F@wnU4`IiuK9(#>9x!G}QH)JWL zad#4ZR4WKas5c0^Uxg)hR|C^<`Mn&HMmx=k&pL_?WtdXM_7vDI7YBf>_R;N348&rf zIbm}b*4CE(YEJvC3te6=ZfdHN^@>JQBn%BHMXzYn;$a1h?-2B5!KFxmFWT>Nvqr45UPmw_(YNm0M+{A?g;R*ZAM7Jszfl+TVa*VmkejK;4|v;{kc%lNjd-$=Cl^$vE-XAVOV;riSV_$|@^L*Z}FzYMiHa6;G$ZI&?{*f&1lUgO{YZEQ&NCu`a#CTGrkk>+D zLX=eVNS+QTxHW}Sg{I*T9_Aj7sAEMWQU$)y#oz7uv5La$Wjfk-O##%~@0Or{A7zA= z>Y8fE#)}9%1%FZbvt?2M3@DfnZ29s+1NT7pkd1?buy1T$i3;2Xz>A~AP_VSL1U4oW z6_wW3R#5N@^PicRnB+?Mt&imz@z=jE0b1PkK}j3zvFAa@)YJvgnkx)jDMcLhjg8+| z9|2z)?DcCwUS7JT7ifPyavKY9OtI$ITX2`phOM6}Dk{o+t*xzJzI>^uh>j8Qh;E6_ z-}66+xJVcg8TjQe^-oM4W{+j25wfpFsic%RAjj(?S4TrUI;v`F1pFG3>tGPU|ivND*dJL#PWNhBS>04W2$eY3gM! zK)j(C=*xI@mTFZzKtcj@bp1V9zO2W%#HR7JhdG%??#UA&`>7Yg=!;iDp#|#FWN9z< sDjjBpsj0I~?{bO~zi!Z5UejWfeCeRN6KMfg{}G-(QI-2FV;uZH0ON>FkN^Mx From 2150a2bb55f9116bcb16c391d0018d269a741abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 12 Aug 2017 18:42:14 +0300 Subject: [PATCH 322/492] #590 Skip puml processing for singleton module --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 4f4b5dee6..0ea198c3f 100644 --- a/pom.xml +++ b/pom.xml @@ -460,6 +460,7 @@ java-design-patterns + singleton From 002774b5aa8db75f53fc5205d8bd14977d077f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 12 Aug 2017 19:24:55 +0300 Subject: [PATCH 323/492] Fix Travis out of memory error --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 817b6635f..a2aaf764b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,4 +36,4 @@ notifications: on_failure: always # options: [always|never|change] default: always on_start: never # options: [always|never|change] default: always -sudo: false # route the build to the container-based infrastructure for a faster build +sudo: required \ No newline at end of file From 2d750dc0fdfc848e67d5f9a8524b5a19817401e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 12 Aug 2017 20:02:14 +0300 Subject: [PATCH 324/492] #590 Alter Factory Method presentation --- factory-method/README.md | 41 +++++++- factory-method/etc/factory-method.png | Bin 22316 -> 0 bytes factory-method/etc/factory-method.ucls | 117 --------------------- factory-method/etc/factory-method.urm.puml | 54 ---------- factory-method/etc/factory-method_1.png | Bin 47622 -> 0 bytes pom.xml | 1 + 6 files changed, 41 insertions(+), 172 deletions(-) delete mode 100644 factory-method/etc/factory-method.png delete mode 100644 factory-method/etc/factory-method.ucls delete mode 100644 factory-method/etc/factory-method.urm.puml delete mode 100644 factory-method/etc/factory-method_1.png diff --git a/factory-method/README.md b/factory-method/README.md index 17e0818e9..de3a9dd8c 100644 --- a/factory-method/README.md +++ b/factory-method/README.md @@ -19,7 +19,46 @@ Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. -![alt text](./etc/factory-method_1.png "Factory Method") +## Explanation + +Real world example +> Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons. Depending on the customer at hand the right type of blacksmith is summoned. + +In plain words +> It provides a way to delegate the instantiation logic to child classes. + +Wikipedia says +> In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor. + + **Programmatic Example** + +Taking our blacksmith example above. First of all we have a blacksmith interface and some implementations for it + +``` +public interface Blacksmith { + Weapon manufactureWeapon(WeaponType weaponType); +} + +public class ElfBlacksmith implements Blacksmith { + public Weapon manufactureWeapon(WeaponType weaponType) { + return new ElfWeapon(weaponType); + } +} + +public class OrcBlacksmith implements Blacksmith { + public Weapon manufactureWeapon(WeaponType weaponType) { + return new OrcWeapon(weaponType); + } +} +``` + +Now as the customers come the correct type of blacksmith is summoned and requested weapons are manufactured +``` +Blacksmith blacksmith = new ElfBlacksmith(); +blacksmith.manufactureWeapon(WeaponType.SPEAR); +blacksmith.manufactureWeapon(WeaponType.AXE); +// Elvish weapons are created +``` ## Applicability Use the Factory Method pattern when diff --git a/factory-method/etc/factory-method.png b/factory-method/etc/factory-method.png deleted file mode 100644 index c2edfd6484ea802895f57e08797c0172bedb0f1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22316 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 JtBW^6{|~uX4SWCq diff --git a/factory-method/etc/factory-method.ucls b/factory-method/etc/factory-method.ucls deleted file mode 100644 index 562437995..000000000 --- a/factory-method/etc/factory-method.ucls +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/factory-method/etc/factory-method.urm.puml b/factory-method/etc/factory-method.urm.puml deleted file mode 100644 index 73a05e178..000000000 --- a/factory-method/etc/factory-method.urm.puml +++ /dev/null @@ -1,54 +0,0 @@ -@startuml -package com.iluwatar.factory.method { - class App { - - LOGGER : Logger {static} - - blacksmith : Blacksmith - + App(blacksmith : Blacksmith) - + main(args : String[]) {static} - - manufactureWeapons() - } - interface Blacksmith { - + manufactureWeapon(WeaponType) : Weapon {abstract} - } - class ElfBlacksmith { - + ElfBlacksmith() - + manufactureWeapon(weaponType : WeaponType) : Weapon - } - class ElfWeapon { - - weaponType : WeaponType - + ElfWeapon(weaponType : WeaponType) - + getWeaponType() : WeaponType - + toString() : String - } - class OrcBlacksmith { - + OrcBlacksmith() - + manufactureWeapon(weaponType : WeaponType) : Weapon - } - class OrcWeapon { - - weaponType : WeaponType - + OrcWeapon(weaponType : WeaponType) - + getWeaponType() : WeaponType - + toString() : String - } - interface Weapon { - + getWeaponType() : WeaponType {abstract} - } - enum WeaponType { - + AXE {static} - + SHORT_SWORD {static} - + SPEAR {static} - + UNDEFINED {static} - - title : String - + toString() : String - + valueOf(name : String) : WeaponType {static} - + values() : WeaponType[] {static} - } -} -ElfWeapon --> "-weaponType" WeaponType -OrcWeapon --> "-weaponType" WeaponType -App --> "-blacksmith" Blacksmith -ElfBlacksmith ..|> Blacksmith -ElfWeapon ..|> Weapon -OrcBlacksmith ..|> Blacksmith -OrcWeapon ..|> Weapon -@enduml \ No newline at end of file diff --git a/factory-method/etc/factory-method_1.png b/factory-method/etc/factory-method_1.png deleted file mode 100644 index 6b9276781be2e1f498f590a7877a6434204caa41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47622 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 E0=f?*lK=n! diff --git a/pom.xml b/pom.xml index 0ea198c3f..7f96043f5 100644 --- a/pom.xml +++ b/pom.xml @@ -461,6 +461,7 @@ java-design-patterns singleton + factory-method From fba30e59ee8f0a82c577493ed0b2089ae4afae6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 12 Aug 2017 21:44:21 +0300 Subject: [PATCH 325/492] #590 Kramdown fixes --- factory-method/README.md | 5 ++++- singleton/README.md | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/factory-method/README.md b/factory-method/README.md index de3a9dd8c..07c92d0e5 100644 --- a/factory-method/README.md +++ b/factory-method/README.md @@ -20,14 +20,16 @@ decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. ## Explanation - Real world example + > Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons. Depending on the customer at hand the right type of blacksmith is summoned. In plain words + > It provides a way to delegate the instantiation logic to child classes. Wikipedia says + > In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor. **Programmatic Example** @@ -53,6 +55,7 @@ public class OrcBlacksmith implements Blacksmith { ``` Now as the customers come the correct type of blacksmith is summoned and requested weapons are manufactured + ``` Blacksmith blacksmith = new ElfBlacksmith(); blacksmith.manufactureWeapon(WeaponType.SPEAR); diff --git a/singleton/README.md b/singleton/README.md index 0a81ba0fc..1be304d8e 100644 --- a/singleton/README.md +++ b/singleton/README.md @@ -18,24 +18,31 @@ access to it. ## Explanation Real world example + > There can only be one ivory tower where the wizards study their magic. The same enchanted ivory tower is always used by the wizards. Ivory tower here is singleton. In plain words + > Ensures that only one object of a particular class is ever created. Wikipedia says + > In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. **Programmatic Example** Joshua Bloch, Effective Java 2nd Edition p.18 + > A single-element enum type is the best way to implement a singleton + ``` public enum EnumIvoryTower { INSTANCE; } ``` + Then in order to use + ``` EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE; EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE; From 4b3435c550def35d2b55cdb72ffa44410efca7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20Hamzao=C4=9Fullar=C4=B1?= Date: Sun, 13 Aug 2017 00:08:35 +0300 Subject: [PATCH 326/492] Code formating --- event-sourcing/etc/.gitkeep | 0 event-sourcing/etc/event-sourcing.urm.puml | 184 +++++++++++ event-sourcing/src/.gitkeep | 0 .../event/sourcing/api/DomainEvent.java | 108 +++++-- .../event/sourcing/api/EventProcessor.java | 44 ++- .../event/sourcing/api/ProcessorJournal.java | 44 ++- .../com/iluwatar/event/sourcing/app/App.java | 89 ++++-- .../event/sourcing/domain/Account.java | 295 ++++++++++++------ .../event/sourcing/domain/Transaction.java | 114 +++++-- .../sourcing/event/AccountCreateEvent.java | 83 +++-- .../sourcing/event/MoneyDepositEvent.java | 82 +++-- .../sourcing/event/MoneyTransferEvent.java | 117 ++++--- .../sourcing/event/MoneyWithdrawalEvent.java | 82 +++-- .../gateway/AccountCreateContractSender.java | 34 +- .../event/sourcing/gateway/Gateways.java | 49 ++- .../sourcing/gateway/TransactionLogger.java | 34 +- .../sourcing/journal/JsonFileJournal.java | 183 ++++++----- .../processor/DomainEventProcessor.java | 64 ++-- .../sourcing/service/AccountService.java | 52 ++- .../service/MoneyTransactionService.java | 84 ++++- .../sourcing/service/SequenceIdGenerator.java | 38 ++- .../sourcing/state/AccountAggregate.java | 64 +++- 22 files changed, 1396 insertions(+), 448 deletions(-) delete mode 100644 event-sourcing/etc/.gitkeep create mode 100644 event-sourcing/etc/event-sourcing.urm.puml delete mode 100644 event-sourcing/src/.gitkeep diff --git a/event-sourcing/etc/.gitkeep b/event-sourcing/etc/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/event-sourcing/etc/event-sourcing.urm.puml b/event-sourcing/etc/event-sourcing.urm.puml new file mode 100644 index 000000000..207d238e6 --- /dev/null +++ b/event-sourcing/etc/event-sourcing.urm.puml @@ -0,0 +1,184 @@ +@startuml +package com.iluwatar.event.sourcing.journal { + class JsonFileJournal { + - aFile : File + - events : List + - index : int + + JsonFileJournal() + + readNext() : DomainEvent + + reset() + + write(domainEvent : DomainEvent) + } +} +package com.iluwatar.event.sourcing.processor { + class DomainEventProcessor { + - precessorJournal : ProcessorJournal + + DomainEventProcessor() + + process(domainEvent : DomainEvent) + + recover() + + setPrecessorJournal(precessorJournal : ProcessorJournal) + } +} +package com.iluwatar.event.sourcing.service { + class AccountService { + - eventProcessor : EventProcessor + + AccountService(eventProcessor : EventProcessor) + + createAccount(accountNo : int, owner : String) + } + class MoneyTransactionService { + - eventProcessor : EventProcessor + + MoneyTransactionService(eventProcessor : EventProcessor) + + depositMoney(accountNo : int, money : BigDecimal) + + transferMoney(accountNoFrom : int, accountNoTo : int, money : BigDecimal) + + withdrawalMoney(accountNo : int, money : BigDecimal) + } + class SequenceIdGenerator { + - sequenceId : long {static} + + SequenceIdGenerator() + + nextSequenceId() : long {static} + } +} +package com.iluwatar.event.sourcing.event { + class AccountCreateEvent { + - accountNo : int + - owner : String + + AccountCreateEvent(sequenceId : long, createdTime : long, accountNo : int, owner : String) + + getAccountNo() : int + + getOwner() : String + + process() + } + class MoneyDepositEvent { + - accountNo : int + - money : BigDecimal + + MoneyDepositEvent(sequenceId : long, createdTime : long, accountNo : int, money : BigDecimal) + + getAccountNo() : int + + getMoney() : BigDecimal + + process() + } + class MoneyTransferEvent { + - accountNoFrom : int + - accountNoTo : int + - money : BigDecimal + + MoneyTransferEvent(sequenceId : long, createdTime : long, money : BigDecimal, accountNoFrom : int, accountNoTo : int) + + getAccountNoFrom() : int + + getAccountNoTo() : int + + getMoney() : BigDecimal + + process() + } + class MoneyWithdrawalEvent { + - accountNo : int + - money : BigDecimal + + MoneyWithdrawalEvent(sequenceId : long, createdTime : long, accountNo : int, money : BigDecimal) + + getAccountNo() : int + + getMoney() : BigDecimal + + process() + } +} +package com.iluwatar.event.sourcing.gateway { + class AccountCreateContractSender { + + AccountCreateContractSender() + + sendContractInfo(account : Account) + } + class Gateways { + - accountCreateContractSender : AccountCreateContractSender {static} + - transactionLogger : TransactionLogger {static} + + Gateways() + + getAccountCreateContractSender() : AccountCreateContractSender {static} + + getTransactionLogger() : TransactionLogger {static} + } + class TransactionLogger { + + TransactionLogger() + + log(transaction : Transaction) + } +} +package com.iluwatar.event.sourcing.app { + class App { + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.event.sourcing.state { + class AccountAggregate { + - accounts : Map {static} + + AccountAggregate() + + getAccount(accountNo : int) : Account {static} + + putAccount(account : Account) {static} + + resetState() {static} + } +} +package com.iluwatar.event.sourcing.domain { + class Account { + - accountNo : int + - money : BigDecimal + - owner : String + - transactions : List + + Account(accountNo : int, owner : String) + + copy() : Account + - depositMoney(money : BigDecimal) : Transaction + + getAccountNo() : int + + getMoney() : BigDecimal + + getOwner() : String + + getTransactions() : List + - handleDeposit(money : BigDecimal, realTime : boolean) + + handleEvent(accountCreateEvent : AccountCreateEvent) + + handleEvent(moneyDepositEvent : MoneyDepositEvent) + + handleEvent(moneyWithdrawalEvent : MoneyWithdrawalEvent) + + handleTransferFromEvent(moneyTransferEvent : MoneyTransferEvent) + + handleTransferToEvent(moneyTransferEvent : MoneyTransferEvent) + - handleWithdrawal(money : BigDecimal, realTime : boolean) + + setMoney(money : BigDecimal) + + setTransactions(transactions : List) + + toString() : String + - withdrawMoney(money : BigDecimal) : Transaction + } + class Transaction { + - accountNo : int + - lastBalance : BigDecimal + - moneyIn : BigDecimal + - moneyOut : BigDecimal + + Transaction(accountNo : int, moneyIn : BigDecimal, moneyOut : BigDecimal, lastBalance : BigDecimal) + + getAccountNo() : int + + getLastBalance() : BigDecimal + + getMoneyIn() : BigDecimal + + getMoneyOut() : BigDecimal + + toString() : String + } +} +package com.iluwatar.event.sourcing.api { + abstract class DomainEvent { + - createdTime : long + - eventClassName : String + - realTime : boolean + - sequenceId : long + + DomainEvent(sequenceId : long, createdTime : long, eventClassName : String) + + getCreatedTime() : long + + getEventClassName() : String + + getSequenceId() : long + + isRealTime() : boolean + + process() {abstract} + + setRealTime(realTime : boolean) + } + interface EventProcessor { + + process(DomainEvent) {abstract} + + recover() {abstract} + + setPrecessorJournal(ProcessorJournal) {abstract} + } + interface ProcessorJournal { + + readNext() : DomainEvent {abstract} + + reset() {abstract} + + write(DomainEvent) {abstract} + } +} +Gateways --> "-accountCreateContractSender" AccountCreateContractSender +DomainEventProcessor --> "-precessorJournal" ProcessorJournal +Account --> "-transactions" Transaction +Gateways --> "-transactionLogger" TransactionLogger +AccountService --> "-eventProcessor" EventProcessor +MoneyTransactionService --> "-eventProcessor" EventProcessor +AccountCreateEvent --|> DomainEvent +MoneyDepositEvent --|> DomainEvent +MoneyTransferEvent --|> DomainEvent +MoneyWithdrawalEvent --|> DomainEvent +JsonFileJournal ..|> ProcessorJournal +DomainEventProcessor ..|> EventProcessor +@enduml \ No newline at end of file diff --git a/event-sourcing/src/.gitkeep b/event-sourcing/src/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java index e20d03232..693ea1755 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.api; import java.io.Serializable; @@ -6,36 +28,72 @@ import java.io.Serializable; * Created by serdarh on 06.08.2017. */ public abstract class DomainEvent implements Serializable { - private final long sequenceId; - private final long createdTime; - private boolean realTime = true; - private final String eventClassName; - public DomainEvent(long sequenceId, long createdTime, String eventClassName) { - this.sequenceId = sequenceId; - this.createdTime = createdTime; - this.eventClassName = eventClassName; - } + private final long sequenceId; + private final long createdTime; + private final String eventClassName; + private boolean realTime = true; - public long getSequenceId() { - return sequenceId; - } + /** + * Instantiates a new Domain event. + * + * @param sequenceId the sequence id + * @param createdTime the created time + * @param eventClassName the event class name + */ + public DomainEvent(long sequenceId, long createdTime, String eventClassName) { + this.sequenceId = sequenceId; + this.createdTime = createdTime; + this.eventClassName = eventClassName; + } - public long getCreatedTime() { - return createdTime; - } + /** + * Gets sequence id. + * + * @return the sequence id + */ + public long getSequenceId() { + return sequenceId; + } - public boolean isRealTime() { - return realTime; - } + /** + * Gets created time. + * + * @return the created time + */ + public long getCreatedTime() { + return createdTime; + } - public void setRealTime(boolean realTime) { - this.realTime = realTime; - } + /** + * Is real time boolean. + * + * @return the boolean + */ + public boolean isRealTime() { + return realTime; + } - public abstract void process(); + /** + * Sets real time. + * + * @param realTime the real time + */ + public void setRealTime(boolean realTime) { + this.realTime = realTime; + } - public String getEventClassName() { - return eventClassName; - } + /** + * Process. + */ + public abstract void process(); + + /** + * Gets event class name. + * + * @return the event class name + */ + public String getEventClassName() { + return eventClassName; + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java index 0fc673bf4..afa218939 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java @@ -1,10 +1,48 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.api; /** * Created by serdarh on 06.08.2017. */ public interface EventProcessor { - void process(DomainEvent domainEvent); - void setPrecessorJournal(ProcessorJournal precessorJournal); - void recover(); + + /** + * Process. + * + * @param domainEvent the domain event + */ + void process(DomainEvent domainEvent); + + /** + * Sets precessor journal. + * + * @param precessorJournal the precessor journal + */ + void setPrecessorJournal(ProcessorJournal precessorJournal); + + /** + * Recover. + */ + void recover(); } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java index 906c66247..8814b82d9 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java @@ -1,10 +1,48 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.api; /** * Created by serdarh on 06.08.2017. */ public interface ProcessorJournal { - void write(DomainEvent domainEvent); - void reset(); - DomainEvent readNext(); + + /** + * Write. + * + * @param domainEvent the domain event + */ + void write(DomainEvent domainEvent); + + /** + * Reset. + */ + void reset(); + + /** + * Read next domain event. + * + * @return the domain event + */ + DomainEvent readNext(); } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java index 8627736f1..f62cebb62 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.app; import com.iluwatar.event.sourcing.journal.JsonFileJournal; @@ -5,7 +27,6 @@ import com.iluwatar.event.sourcing.processor.DomainEventProcessor; import com.iluwatar.event.sourcing.service.AccountService; import com.iluwatar.event.sourcing.service.MoneyTransactionService; import com.iluwatar.event.sourcing.state.AccountAggregate; - import java.math.BigDecimal; /** @@ -13,46 +34,52 @@ import java.math.BigDecimal; */ public class App { - public static void main(String[] args) { - System.out.println("Running the system first time............"); + /** + * The entry point of application. + * + * @param args the input arguments + */ + public static void main(String[] args) { + System.out.println("Running the system first time............"); - DomainEventProcessor domainEventProcessor = new DomainEventProcessor(); - JsonFileJournal jsonFileJournal = new JsonFileJournal(); - jsonFileJournal.reset(); - domainEventProcessor.setPrecessorJournal(jsonFileJournal); + DomainEventProcessor domainEventProcessor = new DomainEventProcessor(); + JsonFileJournal jsonFileJournal = new JsonFileJournal(); + jsonFileJournal.reset(); + domainEventProcessor.setPrecessorJournal(jsonFileJournal); - System.out.println("Creating th accounts............"); + System.out.println("Creating th accounts............"); - AccountService accountService = new AccountService(domainEventProcessor); - MoneyTransactionService moneyTransactionService = new MoneyTransactionService(domainEventProcessor); - accountService.createAccount(1,"Daenerys Targaryen"); - accountService.createAccount(2,"Jon Snow"); + AccountService accountService = new AccountService(domainEventProcessor); + MoneyTransactionService moneyTransactionService = new MoneyTransactionService( + domainEventProcessor); + accountService.createAccount(1, "Daenerys Targaryen"); + accountService.createAccount(2, "Jon Snow"); - System.out.println("Do some money operations............"); + System.out.println("Do some money operations............"); - moneyTransactionService.depositMoney(1,new BigDecimal("100000")); - moneyTransactionService.depositMoney(2,new BigDecimal("10")); + moneyTransactionService.depositMoney(1, new BigDecimal("100000")); + moneyTransactionService.depositMoney(2, new BigDecimal("100")); - moneyTransactionService.transferMoney(1,2,new BigDecimal("10000")); - moneyTransactionService.withdrawalMoney(2, new BigDecimal("1000")); + moneyTransactionService.transferMoney(1, 2, new BigDecimal("10000")); + moneyTransactionService.withdrawalMoney(2, new BigDecimal("1000")); - System.out.println("...............State:............"); - System.out.println(AccountAggregate.getAccount(1)); - System.out.println(AccountAggregate.getAccount(2)); + System.out.println("...............State:............"); + System.out.println(AccountAggregate.getAccount(1)); + System.out.println(AccountAggregate.getAccount(2)); - System.out.println("At that point system goes down state in memory cleared............"); + System.out.println("At that point system goes down state in memory cleared............"); - AccountAggregate.resetState(); + AccountAggregate.resetState(); - System.out.println("Recover the syste by the events in journal file............"); + System.out.println("Recover the syste by the events in journal file............"); - domainEventProcessor = new DomainEventProcessor(); - jsonFileJournal = new JsonFileJournal(); - domainEventProcessor.setPrecessorJournal(jsonFileJournal); - domainEventProcessor.recover(); + domainEventProcessor = new DomainEventProcessor(); + jsonFileJournal = new JsonFileJournal(); + domainEventProcessor.setPrecessorJournal(jsonFileJournal); + domainEventProcessor.recover(); - System.out.println("...............State Recovered:............"); - System.out.println(AccountAggregate.getAccount(1)); - System.out.println(AccountAggregate.getAccount(2)); - } + System.out.println("...............State Recovered:............"); + System.out.println(AccountAggregate.getAccount(1)); + System.out.println(AccountAggregate.getAccount(2)); + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java index 48cda1eca..9e1bc560e 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.domain; import com.iluwatar.event.sourcing.event.AccountCreateEvent; @@ -6,7 +28,6 @@ import com.iluwatar.event.sourcing.event.MoneyTransferEvent; import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent; import com.iluwatar.event.sourcing.gateway.Gateways; import com.iluwatar.event.sourcing.state.AccountAggregate; - import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -15,116 +36,184 @@ import java.util.List; * Created by serdarh on 06.08.2017. */ public class Account { - private final int accountNo; - private final String owner; - private BigDecimal money; - private List transactions; - public Account(int accountNo, String owner) { - this.accountNo = accountNo; - this.owner = owner; - money = BigDecimal.ZERO; - transactions = new ArrayList<>(); + private final int accountNo; + private final String owner; + private BigDecimal money; + private List transactions; + + /** + * Instantiates a new Account. + * + * @param accountNo the account no + * @param owner the owner + */ + public Account(int accountNo, String owner) { + this.accountNo = accountNo; + this.owner = owner; + money = BigDecimal.ZERO; + transactions = new ArrayList<>(); + } + + /** + * Gets account no. + * + * @return the account no + */ + public int getAccountNo() { + return accountNo; + } + + /** + * Gets owner. + * + * @return the owner + */ + public String getOwner() { + return owner; + } + + /** + * Gets money. + * + * @return the money + */ + public BigDecimal getMoney() { + return money; + } + + /** + * Sets money. + * + * @param money the money + */ + public void setMoney(BigDecimal money) { + this.money = money; + } + + /** + * Gets transactions. + * + * @return the transactions + */ + public List getTransactions() { + return transactions; + } + + /** + * Sets transactions. + * + * @param transactions the transactions + */ + public void setTransactions(List transactions) { + this.transactions = transactions; + } + + /** + * Copy account. + * + * @return the account + */ + public Account copy() { + Account account = new Account(accountNo, owner); + account.setMoney(money); + account.setTransactions(transactions); + return account; + } + + @Override + public String toString() { + return "Account{" + + "accountNo=" + accountNo + + ", owner='" + owner + '\'' + + ", money=" + money + + ", transactions=" + transactions + + '}'; + } + + private Transaction depositMoney(BigDecimal money) { + this.money = this.money.add(money); + Transaction transaction = new Transaction(accountNo, money, BigDecimal.ZERO, this.money); + transactions.add(transaction); + return transaction; + } + + private Transaction withdrawMoney(BigDecimal money) { + this.money = this.money.subtract(money); + Transaction transaction = new Transaction(accountNo, BigDecimal.ZERO, money, this.money); + transactions.add(transaction); + return transaction; + } + + private void handleDeposit(BigDecimal money, boolean realTime) { + Transaction transaction = depositMoney(money); + AccountAggregate.putAccount(this); + if (realTime) { + Gateways.getTransactionLogger().log(transaction); + } + } + + private void handleWithdrawal(BigDecimal money, boolean realTime) { + if (this.money.compareTo(money) == -1) { + throw new RuntimeException("Insufficient Account Balance"); } - public int getAccountNo() { - return accountNo; + Transaction transaction = withdrawMoney(money); + AccountAggregate.putAccount(this); + if (realTime) { + Gateways.getTransactionLogger().log(transaction); } + } - public String getOwner() { - return owner; + /** + * Handle event. + * + * @param moneyDepositEvent the money deposit event + */ + public void handleEvent(MoneyDepositEvent moneyDepositEvent) { + handleDeposit(moneyDepositEvent.getMoney(), moneyDepositEvent.isRealTime()); + } + + + /** + * Handle event. + * + * @param moneyWithdrawalEvent the money withdrawal event + */ + public void handleEvent(MoneyWithdrawalEvent moneyWithdrawalEvent) { + handleWithdrawal(moneyWithdrawalEvent.getMoney(), moneyWithdrawalEvent.isRealTime()); + } + + /** + * Handle event. + * + * @param accountCreateEvent the account create event + */ + public void handleEvent(AccountCreateEvent accountCreateEvent) { + AccountAggregate.putAccount(this); + // check if this event is replicated from journal before calling an external gateway function + if (accountCreateEvent.isRealTime()) { + Gateways.getAccountCreateContractSender().sendContractInfo(this); } + } - public BigDecimal getMoney() { - return money; - } + /** + * Handle transfer from event. + * + * @param moneyTransferEvent the money transfer event + */ + public void handleTransferFromEvent(MoneyTransferEvent moneyTransferEvent) { + handleWithdrawal(moneyTransferEvent.getMoney(), moneyTransferEvent.isRealTime()); + } - public List getTransactions() { - return transactions; - } - - public void setMoney(BigDecimal money) { - this.money = money; - } - - public void setTransactions(List transactions) { - this.transactions = transactions; - } - - public Account copy() { - Account account = new Account(accountNo, owner); - account.setMoney(money); - account.setTransactions(transactions); - return account; - } - - @Override - public String toString() { - return "Account{" + - "accountNo=" + accountNo + - ", owner='" + owner + '\'' + - ", money=" + money + - ", transactions=" + transactions + - '}'; - } - - private Transaction depositMoney(BigDecimal money) { - this.money = this.money.add(money); - Transaction transaction = new Transaction(accountNo,money,BigDecimal.ZERO,this.money); - transactions.add(transaction); - return transaction; - } - - private Transaction withdrawMoney(BigDecimal money) { - this.money = this.money.subtract(money); - Transaction transaction = new Transaction(accountNo,BigDecimal.ZERO,money,this.money); - transactions.add(transaction); - return transaction; - } - - private void handleDeposit(BigDecimal money,boolean realTime) { - Transaction transaction = depositMoney(money); - AccountAggregate.putAccount(this); - if(realTime) { - Gateways.getTransactionLogger().log(transaction); - } - } - - private void handleWithdrawal(BigDecimal money, boolean realTime) { - if(this.money.compareTo(money)==-1){ - throw new RuntimeException("Insufficient Account Balance"); - } - - Transaction transaction = withdrawMoney(money); - AccountAggregate.putAccount(this); - if(realTime) { - Gateways.getTransactionLogger().log(transaction); - } - } - - public void handleEvent(MoneyDepositEvent moneyDepositEvent) { - handleDeposit(moneyDepositEvent.getMoney(),moneyDepositEvent.isRealTime()); - } + /** + * Handle transfer to event. + * + * @param moneyTransferEvent the money transfer event + */ + public void handleTransferToEvent(MoneyTransferEvent moneyTransferEvent) { + handleDeposit(moneyTransferEvent.getMoney(), moneyTransferEvent.isRealTime()); + } - public void handleEvent(MoneyWithdrawalEvent moneyWithdrawalEvent) { - handleWithdrawal(moneyWithdrawalEvent.getMoney(),moneyWithdrawalEvent.isRealTime()); - } - - - public void handleTransferFromEvent(MoneyTransferEvent moneyTransferEvent) { - handleWithdrawal(moneyTransferEvent.getMoney(),moneyTransferEvent.isRealTime()); - } - - public void handleTransferToEvent(MoneyTransferEvent moneyTransferEvent) { - handleDeposit(moneyTransferEvent.getMoney(),moneyTransferEvent.isRealTime()); - } - - public void handleEvent(AccountCreateEvent accountCreateEvent) { - AccountAggregate.putAccount(this); - // check if this event is replicated from journal before calling an external gateway function - if(accountCreateEvent.isRealTime()) { - Gateways.getAccountCreateContractSender().sendContractInfo(this); - } - } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java index 557efbedc..29cdc4d15 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.domain; import java.math.BigDecimal; @@ -6,41 +28,71 @@ import java.math.BigDecimal; * Created by serdarh on 06.08.2017. */ public class Transaction { - private final int accountNo; - private final BigDecimal moneyIn; - private final BigDecimal moneyOut; - private final BigDecimal lastBalance; - public Transaction(int accountNo, BigDecimal moneyIn, BigDecimal moneyOut, BigDecimal lastBalance) { - this.accountNo = accountNo; - this.moneyIn = moneyIn; - this.moneyOut = moneyOut; - this.lastBalance = lastBalance; - } + private final int accountNo; + private final BigDecimal moneyIn; + private final BigDecimal moneyOut; + private final BigDecimal lastBalance; - public int getAccountNo() { - return accountNo; - } + /** + * Instantiates a new Transaction. + * + * @param accountNo the account no + * @param moneyIn the money in + * @param moneyOut the money out + * @param lastBalance the last balance + */ + public Transaction(int accountNo, BigDecimal moneyIn, BigDecimal moneyOut, + BigDecimal lastBalance) { + this.accountNo = accountNo; + this.moneyIn = moneyIn; + this.moneyOut = moneyOut; + this.lastBalance = lastBalance; + } - public BigDecimal getMoneyIn() { - return moneyIn; - } + /** + * Gets account no. + * + * @return the account no + */ + public int getAccountNo() { + return accountNo; + } - public BigDecimal getMoneyOut() { - return moneyOut; - } + /** + * Gets money in. + * + * @return the money in + */ + public BigDecimal getMoneyIn() { + return moneyIn; + } - public BigDecimal getLastBalance() { - return lastBalance; - } + /** + * Gets money out. + * + * @return the money out + */ + public BigDecimal getMoneyOut() { + return moneyOut; + } - @Override - public String toString() { - return "Transaction{" + - "accountNo=" + accountNo + - ", moneyIn=" + moneyIn + - ", moneyOut=" + moneyOut + - ", lastBalance=" + lastBalance + - '}'; - } + /** + * Gets last balance. + * + * @return the last balance + */ + public BigDecimal getLastBalance() { + return lastBalance; + } + + @Override + public String toString() { + return "Transaction{" + + "accountNo=" + accountNo + + ", moneyIn=" + moneyIn + + ", moneyOut=" + moneyOut + + ", lastBalance=" + lastBalance + + '}'; + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java index 1ea089e2f..8356cd3e8 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; @@ -8,30 +30,49 @@ import com.iluwatar.event.sourcing.state.AccountAggregate; * Created by serdarh on 06.08.2017. */ public class AccountCreateEvent extends DomainEvent { - private final int accountNo; - private final String owner; - public AccountCreateEvent(long sequenceId, long createdTime, int accountNo, String owner) { - super(sequenceId, createdTime, "AccountCreateEvent"); - this.accountNo = accountNo; - this.owner = owner; - } + private final int accountNo; + private final String owner; - public int getAccountNo() { - return accountNo; - } + /** + * Instantiates a new Account create event. + * + * @param sequenceId the sequence id + * @param createdTime the created time + * @param accountNo the account no + * @param owner the owner + */ + public AccountCreateEvent(long sequenceId, long createdTime, int accountNo, String owner) { + super(sequenceId, createdTime, "AccountCreateEvent"); + this.accountNo = accountNo; + this.owner = owner; + } - public String getOwner() { - return owner; - } + /** + * Gets account no. + * + * @return the account no + */ + public int getAccountNo() { + return accountNo; + } - @Override - public void process() { - Account account = AccountAggregate.getAccount(accountNo); - if(account!=null){ - throw new RuntimeException("Account already exists"); - } - account = new Account(accountNo,owner); - account.handleEvent(this); + /** + * Gets owner. + * + * @return the owner + */ + public String getOwner() { + return owner; + } + + @Override + public void process() { + Account account = AccountAggregate.getAccount(accountNo); + if (account != null) { + throw new RuntimeException("Account already exists"); } + account = new Account(accountNo, owner); + account.handleEvent(this); + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java index 384a9e198..9d73639eb 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java @@ -1,38 +1,78 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; import com.iluwatar.event.sourcing.state.AccountAggregate; - import java.math.BigDecimal; /** * Created by serdarh on 06.08.2017. */ public class MoneyDepositEvent extends DomainEvent { - private BigDecimal money; - private int accountNo; - public MoneyDepositEvent(long sequenceId, long createdTime, int accountNo,BigDecimal money) { - super(sequenceId, createdTime, "MoneyDepositEvent"); - this.money = money; - this.accountNo = accountNo; - } + private BigDecimal money; + private int accountNo; - public BigDecimal getMoney() { - return money; - } + /** + * Instantiates a new Money deposit event. + * + * @param sequenceId the sequence id + * @param createdTime the created time + * @param accountNo the account no + * @param money the money + */ + public MoneyDepositEvent(long sequenceId, long createdTime, int accountNo, BigDecimal money) { + super(sequenceId, createdTime, "MoneyDepositEvent"); + this.money = money; + this.accountNo = accountNo; + } - public int getAccountNo() { - return accountNo; - } + /** + * Gets money. + * + * @return the money + */ + public BigDecimal getMoney() { + return money; + } - @Override - public void process() { - Account account = AccountAggregate.getAccount(accountNo); - if(account==null){ - throw new RuntimeException("Account not found"); - } - account.handleEvent(this); + /** + * Gets account no. + * + * @return the account no + */ + public int getAccountNo() { + return accountNo; + } + + @Override + public void process() { + Account account = AccountAggregate.getAccount(accountNo); + if (account == null) { + throw new RuntimeException("Account not found"); } + account.handleEvent(this); + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java index 6c873d4db..995fb9326 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java @@ -1,50 +1,97 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; import com.iluwatar.event.sourcing.state.AccountAggregate; - import java.math.BigDecimal; /** * Created by serdarh on 06.08.2017. */ public class MoneyTransferEvent extends DomainEvent { - private BigDecimal money; - private int accountNoFrom; - private int accountNoTo; - public MoneyTransferEvent(long sequenceId, long createdTime, BigDecimal money, int accountNoFrom, int accountNoTo) { - super(sequenceId, createdTime, "MoneyTransferEvent"); - this.money = money; - this.accountNoFrom = accountNoFrom; - this.accountNoTo = accountNoTo; + private BigDecimal money; + private int accountNoFrom; + private int accountNoTo; + + /** + * Instantiates a new Money transfer event. + * + * @param sequenceId the sequence id + * @param createdTime the created time + * @param money the money + * @param accountNoFrom the account no from + * @param accountNoTo the account no to + */ + public MoneyTransferEvent(long sequenceId, long createdTime, BigDecimal money, int accountNoFrom, + int accountNoTo) { + super(sequenceId, createdTime, "MoneyTransferEvent"); + this.money = money; + this.accountNoFrom = accountNoFrom; + this.accountNoTo = accountNoTo; + } + + /** + * Gets money. + * + * @return the money + */ + public BigDecimal getMoney() { + return money; + } + + /** + * Gets account no from. + * + * @return the account no from + */ + public int getAccountNoFrom() { + return accountNoFrom; + } + + /** + * Gets account no to. + * + * @return the account no to + */ + public int getAccountNoTo() { + return accountNoTo; + } + + @Override + public void process() { + Account accountFrom = AccountAggregate.getAccount(accountNoFrom); + if (accountFrom == null) { + throw new RuntimeException("Account not found " + accountNoFrom); + } + Account accountTo = AccountAggregate.getAccount(accountNoTo); + if (accountTo == null) { + throw new RuntimeException("Account not found" + accountTo); } - public BigDecimal getMoney() { - return money; - } - - public int getAccountNoFrom() { - return accountNoFrom; - } - - public int getAccountNoTo() { - return accountNoTo; - } - - @Override - public void process() { - Account accountFrom = AccountAggregate.getAccount(accountNoFrom); - if(accountFrom==null){ - throw new RuntimeException("Account not found "+accountNoFrom); - } - Account accountTo = AccountAggregate.getAccount(accountNoTo); - if(accountTo==null){ - throw new RuntimeException("Account not found"+ accountTo); - } - - accountFrom.handleTransferFromEvent(this); - accountTo.handleTransferToEvent(this); - } + accountFrom.handleTransferFromEvent(this); + accountTo.handleTransferToEvent(this); + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java index 8ed617008..64fddc16e 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java @@ -1,38 +1,78 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.event; import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; import com.iluwatar.event.sourcing.state.AccountAggregate; - import java.math.BigDecimal; /** * Created by serdarh on 06.08.2017. */ public class MoneyWithdrawalEvent extends DomainEvent { - private BigDecimal money; - private int accountNo; - public MoneyWithdrawalEvent(long sequenceId, long createdTime, int accountNo,BigDecimal money) { - super(sequenceId, createdTime, "MoneyWithdrawalEvent"); - this.money = money; - this.accountNo = accountNo; - } + private BigDecimal money; + private int accountNo; - public BigDecimal getMoney() { - return money; - } + /** + * Instantiates a new Money withdrawal event. + * + * @param sequenceId the sequence id + * @param createdTime the created time + * @param accountNo the account no + * @param money the money + */ + public MoneyWithdrawalEvent(long sequenceId, long createdTime, int accountNo, BigDecimal money) { + super(sequenceId, createdTime, "MoneyWithdrawalEvent"); + this.money = money; + this.accountNo = accountNo; + } - public int getAccountNo() { - return accountNo; - } + /** + * Gets money. + * + * @return the money + */ + public BigDecimal getMoney() { + return money; + } - @Override - public void process() { - Account account = AccountAggregate.getAccount(accountNo); - if(account==null){ - throw new RuntimeException("Account not found"); - } - account.handleEvent(this); + /** + * Gets account no. + * + * @return the account no + */ + public int getAccountNo() { + return accountNo; + } + + @Override + public void process() { + Account account = AccountAggregate.getAccount(accountNo); + if (account == null) { + throw new RuntimeException("Account not found"); } + account.handleEvent(this); + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java index 42dfccf7b..aa15f746f 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.gateway; import com.iluwatar.event.sourcing.domain.Account; @@ -6,7 +28,13 @@ import com.iluwatar.event.sourcing.domain.Account; * Created by serdarh on 06.08.2017. */ public class AccountCreateContractSender { - public void sendContractInfo(Account account){ - // an example imaginary funciton which sends account info to some external end point - } + + /** + * Send contract info. + * + * @param account the account + */ + public void sendContractInfo(Account account) { + // an example imaginary funciton which sends account info to some external end point + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java index d167393bf..932338c32 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java @@ -1,17 +1,50 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.gateway; /** * Created by serdarh on 06.08.2017. */ public class Gateways { - private static AccountCreateContractSender accountCreateContractSender = new AccountCreateContractSender(); - private static TransactionLogger transactionLogger = new TransactionLogger(); - public static AccountCreateContractSender getAccountCreateContractSender() { - return accountCreateContractSender; - } + private static AccountCreateContractSender accountCreateContractSender = new AccountCreateContractSender(); + private static TransactionLogger transactionLogger = new TransactionLogger(); - public static TransactionLogger getTransactionLogger() { - return transactionLogger; - } + /** + * Gets account create contract sender. + * + * @return the account create contract sender + */ + public static AccountCreateContractSender getAccountCreateContractSender() { + return accountCreateContractSender; + } + + /** + * Gets transaction logger. + * + * @return the transaction logger + */ + public static TransactionLogger getTransactionLogger() { + return transactionLogger; + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java index 6d961d96e..3cfea0751 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.gateway; import com.iluwatar.event.sourcing.domain.Transaction; @@ -6,7 +28,13 @@ import com.iluwatar.event.sourcing.domain.Transaction; * Created by serdarh on 06.08.2017. */ public class TransactionLogger { - public void log(Transaction transaction) { - // example imaginary function that logs the transaction to somewhere - } + + /** + * Log. + * + * @param transaction the transaction + */ + public void log(Transaction transaction) { + // example imaginary function that logs the transaction to somewhere + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java index 2d50db55f..a5d82e5be 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.journal; import com.google.gson.Gson; @@ -9,91 +31,104 @@ import com.iluwatar.event.sourcing.event.AccountCreateEvent; import com.iluwatar.event.sourcing.event.MoneyDepositEvent; import com.iluwatar.event.sourcing.event.MoneyTransferEvent; import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent; - -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.util.ArrayList; import java.util.List; /** * Created by serdarh on 06.08.2017. */ -public class JsonFileJournal implements ProcessorJournal{ +public class JsonFileJournal implements ProcessorJournal { - private File aFile; - private List events = new ArrayList<>(); - private int index = 0; - public JsonFileJournal() { - aFile = new File("Journal.json"); - if(aFile.exists()) { - try (BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(aFile), "UTF-8"))) { - String line; - while ((line = input.readLine()) != null) { - events.add(line); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - }else{ - reset(); + private File aFile; + private List events = new ArrayList<>(); + private int index = 0; + + /** + * Instantiates a new Json file journal. + */ + public JsonFileJournal() { + aFile = new File("Journal.json"); + if (aFile.exists()) { + try (BufferedReader input = new BufferedReader( + new InputStreamReader(new FileInputStream(aFile), "UTF-8"))) { + String line; + while ((line = input.readLine()) != null) { + events.add(line); } + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + reset(); + } + } + + @Override + public void write(DomainEvent domainEvent) { + Gson gson = new Gson(); + JsonElement jsonElement; + if (domainEvent instanceof AccountCreateEvent) { + jsonElement = gson.toJsonTree(domainEvent, AccountCreateEvent.class); + } else if (domainEvent instanceof MoneyDepositEvent) { + jsonElement = gson.toJsonTree(domainEvent, MoneyDepositEvent.class); + } else if (domainEvent instanceof MoneyWithdrawalEvent) { + jsonElement = gson.toJsonTree(domainEvent, MoneyWithdrawalEvent.class); + } else if (domainEvent instanceof MoneyTransferEvent) { + jsonElement = gson.toJsonTree(domainEvent, MoneyTransferEvent.class); + } else { + throw new RuntimeException("Journal Event not recegnized"); } - @Override - public void write(DomainEvent domainEvent) { - Gson gson = new Gson(); - JsonElement jsonElement; - if(domainEvent instanceof AccountCreateEvent) { - jsonElement = gson.toJsonTree(domainEvent, AccountCreateEvent.class); - }else if(domainEvent instanceof MoneyDepositEvent) { - jsonElement = gson.toJsonTree(domainEvent, MoneyDepositEvent.class); - }else if(domainEvent instanceof MoneyWithdrawalEvent) { - jsonElement = gson.toJsonTree(domainEvent, MoneyWithdrawalEvent.class); - }else if(domainEvent instanceof MoneyTransferEvent) { - jsonElement = gson.toJsonTree(domainEvent, MoneyTransferEvent.class); - }else{ - throw new RuntimeException("Journal Event not recegnized"); - } + try (Writer output = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(aFile, true), "UTF-8"))) { + String eventString = jsonElement.toString(); + output.write(eventString + "\r\n"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } - try (Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aFile, true), "UTF-8"))) { - String eventString = jsonElement.toString(); - output.write(eventString +"\r\n"); - } catch (IOException e) { - throw new RuntimeException(e); - } + @Override + public void reset() { + aFile.delete(); + } + + + @Override + public DomainEvent readNext() { + if (index >= events.size()) { + return null; + } + String event = events.get(index); + index++; + + JsonParser parser = new JsonParser(); + JsonElement jsonElement = parser.parse(event); + String eventClassName = jsonElement.getAsJsonObject().get("eventClassName").getAsString(); + Gson gson = new Gson(); + DomainEvent domainEvent; + if (eventClassName.equals("AccountCreateEvent")) { + domainEvent = gson.fromJson(jsonElement, AccountCreateEvent.class); + } else if (eventClassName.equals("MoneyDepositEvent")) { + domainEvent = gson.fromJson(jsonElement, MoneyDepositEvent.class); + } else if (eventClassName.equals("MoneyTransferEvent")) { + domainEvent = gson.fromJson(jsonElement, MoneyTransferEvent.class); + } else if (eventClassName.equals("MoneyWithdrawalEvent")) { + domainEvent = gson.fromJson(jsonElement, MoneyWithdrawalEvent.class); + } else { + throw new RuntimeException("Journal Event not recegnized"); } - @Override - public void reset() { - aFile.delete(); - } - - - @Override - public DomainEvent readNext() { - if(index>=events.size()){ - return null; - } - String event = events.get(index); - index++; - - JsonParser parser = new JsonParser(); - JsonElement jsonElement = parser.parse(event); - String eventClassName = jsonElement.getAsJsonObject().get("eventClassName").getAsString(); - Gson gson = new Gson(); - DomainEvent domainEvent; - if(eventClassName.equals("AccountCreateEvent")) { - domainEvent = gson.fromJson(jsonElement, AccountCreateEvent.class); - }else if(eventClassName.equals("MoneyDepositEvent")) { - domainEvent = gson.fromJson(jsonElement, MoneyDepositEvent.class); - }else if(eventClassName.equals("MoneyTransferEvent")) { - domainEvent = gson.fromJson(jsonElement, MoneyTransferEvent.class); - }else if(eventClassName.equals("MoneyWithdrawalEvent")) { - domainEvent = gson.fromJson(jsonElement, MoneyWithdrawalEvent.class); - }else{ - throw new RuntimeException("Journal Event not recegnized"); - } - - domainEvent.setRealTime(false); - return domainEvent; - } + domainEvent.setRealTime(false); + return domainEvent; + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java index 55453b1c6..81ec2e761 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.processor; import com.iluwatar.event.sourcing.api.DomainEvent; @@ -9,29 +31,29 @@ import com.iluwatar.event.sourcing.api.ProcessorJournal; */ public class DomainEventProcessor implements EventProcessor { - private ProcessorJournal precessorJournal; + private ProcessorJournal precessorJournal; - @Override - public void process(DomainEvent domainEvent) { - domainEvent.process(); - precessorJournal.write(domainEvent); - } + @Override + public void process(DomainEvent domainEvent) { + domainEvent.process(); + precessorJournal.write(domainEvent); + } - @Override - public void setPrecessorJournal(ProcessorJournal precessorJournal) { - this.precessorJournal = precessorJournal; - } + @Override + public void setPrecessorJournal(ProcessorJournal precessorJournal) { + this.precessorJournal = precessorJournal; + } - @Override - public void recover() { - DomainEvent domainEvent; - while(true) { - domainEvent = precessorJournal.readNext(); - if(domainEvent==null){ - break; - }else{ - domainEvent.process(); - } - } + @Override + public void recover() { + DomainEvent domainEvent; + while (true) { + domainEvent = precessorJournal.readNext(); + if (domainEvent == null) { + break; + } else { + domainEvent.process(); + } } + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java index b0a707788..59cefaaee 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java @@ -1,22 +1,56 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.service; import com.iluwatar.event.sourcing.api.EventProcessor; import com.iluwatar.event.sourcing.event.AccountCreateEvent; - import java.util.Date; /** * Created by serdarh on 06.08.2017. */ public class AccountService { - private EventProcessor eventProcessor; - public AccountService(EventProcessor eventProcessor) { - this.eventProcessor = eventProcessor; - } + private EventProcessor eventProcessor; - public void createAccount(int accountNo, String owner){ - AccountCreateEvent accountCreateEvent = new AccountCreateEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(),accountNo,owner); - eventProcessor.process(accountCreateEvent); - } + /** + * Instantiates a new Account service. + * + * @param eventProcessor the event processor + */ + public AccountService(EventProcessor eventProcessor) { + this.eventProcessor = eventProcessor; + } + + /** + * Create account. + * + * @param accountNo the account no + * @param owner the owner + */ + public void createAccount(int accountNo, String owner) { + AccountCreateEvent accountCreateEvent = new AccountCreateEvent( + SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, owner); + eventProcessor.process(accountCreateEvent); + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java index 80c2a5a4f..5f7c0e9c7 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java @@ -1,10 +1,31 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.service; import com.iluwatar.event.sourcing.api.EventProcessor; import com.iluwatar.event.sourcing.event.MoneyDepositEvent; import com.iluwatar.event.sourcing.event.MoneyTransferEvent; import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent; - import java.math.BigDecimal; import java.util.Date; @@ -12,24 +33,53 @@ import java.util.Date; * Created by serdarh on 06.08.2017. */ public class MoneyTransactionService { - private EventProcessor eventProcessor; - public MoneyTransactionService(EventProcessor eventProcessor) { - this.eventProcessor = eventProcessor; - } + private EventProcessor eventProcessor; - public void depositMoney(int accountNo, BigDecimal money){ - MoneyDepositEvent moneyDepositEvent = new MoneyDepositEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money); - eventProcessor.process(moneyDepositEvent); - } + /** + * Instantiates a new Money transaction service. + * + * @param eventProcessor the event processor + */ + public MoneyTransactionService(EventProcessor eventProcessor) { + this.eventProcessor = eventProcessor; + } - public void withdrawalMoney(int accountNo, BigDecimal money){ - MoneyWithdrawalEvent moneyWithdrawalEvent = new MoneyWithdrawalEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money); - eventProcessor.process(moneyWithdrawalEvent); - } + /** + * Deposit money. + * + * @param accountNo the account no + * @param money the money + */ + public void depositMoney(int accountNo, BigDecimal money) { + MoneyDepositEvent moneyDepositEvent = new MoneyDepositEvent( + SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money); + eventProcessor.process(moneyDepositEvent); + } - public void transferMoney(int accountNoFrom, int accountNoTo, BigDecimal money){ - MoneyTransferEvent moneyTransferEvent = new MoneyTransferEvent(SequenceIdGenerator.nextSequenceId(), new Date().getTime(), money, accountNoFrom, accountNoTo); - eventProcessor.process(moneyTransferEvent); - } + /** + * Withdrawal money. + * + * @param accountNo the account no + * @param money the money + */ + public void withdrawalMoney(int accountNo, BigDecimal money) { + MoneyWithdrawalEvent moneyWithdrawalEvent = new MoneyWithdrawalEvent( + SequenceIdGenerator.nextSequenceId(), new Date().getTime(), accountNo, money); + eventProcessor.process(moneyWithdrawalEvent); + } + + /** + * Transfer money. + * + * @param accountNoFrom the account no from + * @param accountNoTo the account no to + * @param money the money + */ + public void transferMoney(int accountNoFrom, int accountNoTo, BigDecimal money) { + MoneyTransferEvent moneyTransferEvent = new MoneyTransferEvent( + SequenceIdGenerator.nextSequenceId(), new Date().getTime(), money, accountNoFrom, + accountNoTo); + eventProcessor.process(moneyTransferEvent); + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java index 2eec6a70d..6e1730679 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java @@ -1,14 +1,42 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.service; /** * Created by serdarh on 06.08.2017. */ public class SequenceIdGenerator { - private static long sequenceId = 0L; - public static long nextSequenceId(){ - sequenceId++; - return sequenceId; - } + private static long sequenceId = 0L; + + /** + * Next sequence id long. + * + * @return the long + */ + public static long nextSequenceId() { + sequenceId++; + return sequenceId; + } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java index b927af0e1..a42826160 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java @@ -1,7 +1,28 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing.state; import com.iluwatar.event.sourcing.domain.Account; - import java.util.HashMap; import java.util.Map; @@ -9,21 +30,36 @@ import java.util.Map; * Created by serdarh on 06.08.2017. */ public class AccountAggregate { - private static Map accounts = new HashMap<>(); - public static void putAccount(Account account){ - accounts.put(account.getAccountNo(), account); - } + private static Map accounts = new HashMap<>(); - public static Account getAccount(int accountNo){ - Account account = accounts.get(accountNo); - if(account == null){ - return null; - } - return account.copy(); - } + /** + * Put account. + * + * @param account the account + */ + public static void putAccount(Account account) { + accounts.put(account.getAccountNo(), account); + } - public static void resetState(){ - accounts = new HashMap<>(); + /** + * Gets account. + * + * @param accountNo the account no + * @return the account + */ + public static Account getAccount(int accountNo) { + Account account = accounts.get(accountNo); + if (account == null) { + return null; } + return account.copy(); + } + + /** + * Reset state. + */ + public static void resetState() { + accounts = new HashMap<>(); + } } From eb2a232382f2de3eee5d9a288e67b2ab1c90af44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20Hamzao=C4=9Fullar=C4=B1?= Date: Sun, 13 Aug 2017 01:36:52 +0300 Subject: [PATCH 327/492] README edited --- event-sourcing/README.md | 16 +- event-sourcing/etc/event-sourcing.png | Bin 0 -> 105812 bytes event-sourcing/etc/event-sourcing.ucls | 263 +++++++++++++++++++++++++ 3 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 event-sourcing/etc/event-sourcing.png create mode 100644 event-sourcing/etc/event-sourcing.ucls diff --git a/event-sourcing/README.md b/event-sourcing/README.md index c513d2da9..1079405fa 100644 --- a/event-sourcing/README.md +++ b/event-sourcing/README.md @@ -3,7 +3,7 @@ layout: pattern title: Event Sourcing folder: event-sourcing permalink: /patterns/event-sourcing/ -categories: Concurrency +categories: Architectural tags: - Java - Difficulty Intermediate @@ -11,11 +11,23 @@ tags: --- ## Intent +Instead of storing just the current state of the data in a domain, use an append-only store to record the full series of actions taken on that data. The store acts as the system of record and can be used to materialize the domain objects. This can simplify tasks in complex domains, by avoiding the need to synchronize the data model and the business domain, while improving performance, scalability, and responsiveness. It can also provide consistency for transactional data, and maintain full audit trails and history that can enable compensating actions. + +![alt text](./etc/event-sourcing.png "Event Sourcing") ## Applicability Use the Event Sourcing pattern when -* You have a limited accesibility resource and the asynchronous process is acceptable to reach that +* You need very high performance on persisting your application state even your application state have a complex relational data structure +* You need log of changes of your application state and ability to restore a state of any moment in time. +* You need to debug production problems by replaying the past events. + +## Real world examples + +* [The Lmax Architecture] (https://martinfowler.com/articles/lmax.html) ## Credits +* [Martin Fowler - Event Sourcing] (https://martinfowler.com/eaaDev/EventSourcing.html) +* [Event Sourcing | Microsoft Docs] (https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing) +* [Reference 3: Introducing Event Sourcing] (https://msdn.microsoft.com/en-us/library/jj591559.aspx) diff --git a/event-sourcing/etc/event-sourcing.png b/event-sourcing/etc/event-sourcing.png new file mode 100644 index 0000000000000000000000000000000000000000..ac7192b195fb67b1d67c1b5c0e5fcc3a5cfd6fb0 GIT binary patch literal 105812 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 M|6O9HyGJ!3|Bxmyy?LP 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 literal 0 HcmV?d00001 diff --git a/event-sourcing/etc/event-sourcing.ucls b/event-sourcing/etc/event-sourcing.ucls new file mode 100644 index 000000000..d187b1bb0 --- /dev/null +++ b/event-sourcing/etc/event-sourcing.ucls @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 37b9d45a7404c76e8977757f57455092a35885c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Aug 2017 10:09:26 +0300 Subject: [PATCH 328/492] #590 Add explanation for Abstract Factory --- abstract-factory/README.md | 105 +++++++++++- abstract-factory/etc/abstract-factory.png | Bin 21644 -> 0 bytes abstract-factory/etc/abstract-factory.ucls | 159 ------------------ .../etc/abstract-factory.urm.puml | 89 ---------- abstract-factory/etc/abstract-factory_1.png | Bin 58331 -> 0 bytes pom.xml | 1 + 6 files changed, 102 insertions(+), 252 deletions(-) delete mode 100644 abstract-factory/etc/abstract-factory.png delete mode 100644 abstract-factory/etc/abstract-factory.ucls delete mode 100644 abstract-factory/etc/abstract-factory.urm.puml delete mode 100644 abstract-factory/etc/abstract-factory_1.png diff --git a/abstract-factory/README.md b/abstract-factory/README.md index f153c1202..c049401fc 100644 --- a/abstract-factory/README.md +++ b/abstract-factory/README.md @@ -18,7 +18,107 @@ Kit Provide an interface for creating families of related or dependent objects without specifying their concrete classes. -![alt text](./etc/abstract-factory_1.png "Abstract Factory") +## Explanation +Real world example + +> To create a kingdom we need objects with common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom. + +In plain words + +> A factory of factories; a factory that groups the individual but related/dependent factories together without specifying their concrete classes. + +Wikipedia says + +> The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes + +**Programmatic Example** + +Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the kingdom + +``` +public interface Castle { + String getDescription(); +} +public interface King { + String getDescription(); +} +public interface Army { + String getDescription(); +} + +// Elven implementations -> +public class ElfCastle implements Castle { + static final String DESCRIPTION = "This is the Elven castle!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} +public class ElfKing implements King { + static final String DESCRIPTION = "This is the Elven king!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} +public class ElfArmy implements Army { + static final String DESCRIPTION = "This is the Elven Army!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +// Orcish implementations similarly... + +``` + +Then we have the abstraction and implementations for the kingdom factory + +``` +public interface KingdomFactory { + Castle createCastle(); + King createKing(); + Army createArmy(); +} + +public class ElfKingdomFactory implements KingdomFactory { + public Castle createCastle() { + return new ElfCastle(); + } + public King createKing() { + return new ElfKing(); + } + public Army createArmy() { + return new ElfArmy(); + } +} + +public class OrcKingdomFactory implements KingdomFactory { + public Castle createCastle() { + return new OrcCastle(); + } + public King createKing() { + return new OrcKing(); + } + public Army createArmy() { + return new OrcArmy(); + } +} +``` + +Now we have our abstract factory that lets us make family of related objects i.e. Elven kingdom factory creates Elven castle, king and army etc. + +``` +KingdomFactory factory = new ElfKingdomFactory(); +Castle castle = factory.createCastle(); +King king = factory.createKing(); +Army army = factory.createArmy(); + +castle.getDescription(); // Output: This is the Elven castle! +king.getDescription(); // Output: This is the Elven king! +army.getDescription(); // Output: This is the Elven Army! +``` ## Applicability Use the Abstract Factory pattern when @@ -41,9 +141,6 @@ Use the Abstract Factory pattern when * Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time. - - - ## Real world examples * [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) diff --git a/abstract-factory/etc/abstract-factory.png b/abstract-factory/etc/abstract-factory.png deleted file mode 100644 index c709276b662b0006412938e5b675628d48e92840..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21644 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 diff --git a/abstract-factory/etc/abstract-factory.ucls b/abstract-factory/etc/abstract-factory.ucls deleted file mode 100644 index bdf1e1510..000000000 --- a/abstract-factory/etc/abstract-factory.ucls +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/abstract-factory/etc/abstract-factory.urm.puml b/abstract-factory/etc/abstract-factory.urm.puml deleted file mode 100644 index 7b5e1b701..000000000 --- a/abstract-factory/etc/abstract-factory.urm.puml +++ /dev/null @@ -1,89 +0,0 @@ -@startuml -package com.iluwatar.abstractfactory { - class App { - - LOGGER : Logger {static} - - army : Army - - castle : Castle - - king : King - + App() - + createKingdom(factory : KingdomFactory) - + getArmy() : Army - ~ getArmy(factory : KingdomFactory) : Army - + getCastle() : Castle - ~ getCastle(factory : KingdomFactory) : Castle - + getKing() : King - ~ getKing(factory : KingdomFactory) : King - + main(args : String[]) {static} - - setArmy(army : Army) - - setCastle(castle : Castle) - - setKing(king : King) - } - interface Army { - + getDescription() : String {abstract} - } - interface Castle { - + getDescription() : String {abstract} - } - class ElfArmy { - ~ DESCRIPTION : String {static} - + ElfArmy() - + getDescription() : String - } - class ElfCastle { - ~ DESCRIPTION : String {static} - + ElfCastle() - + getDescription() : String - } - class ElfKing { - ~ DESCRIPTION : String {static} - + ElfKing() - + getDescription() : String - } - class ElfKingdomFactory { - + ElfKingdomFactory() - + createArmy() : Army - + createCastle() : Castle - + createKing() : King - } - interface King { - + getDescription() : String {abstract} - } - interface KingdomFactory { - + createArmy() : Army {abstract} - + createCastle() : Castle {abstract} - + createKing() : King {abstract} - } - class OrcArmy { - ~ DESCRIPTION : String {static} - + OrcArmy() - + getDescription() : String - } - class OrcCastle { - ~ DESCRIPTION : String {static} - + OrcCastle() - + getDescription() : String - } - class OrcKing { - ~ DESCRIPTION : String {static} - + OrcKing() - + getDescription() : String - } - class OrcKingdomFactory { - + OrcKingdomFactory() - + createArmy() : Army - + createCastle() : Castle - + createKing() : King - } -} -App --> "-castle" Castle -App --> "-king" King -App --> "-army" Army -ElfArmy ..|> Army -ElfCastle ..|> Castle -ElfKing ..|> King -ElfKingdomFactory ..|> KingdomFactory -OrcArmy ..|> Army -OrcCastle ..|> Castle -OrcKing ..|> King -OrcKingdomFactory ..|> KingdomFactory -@enduml \ No newline at end of file diff --git a/abstract-factory/etc/abstract-factory_1.png b/abstract-factory/etc/abstract-factory_1.png deleted file mode 100644 index 5990edd831264f2084ee888ddba7447707622726..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58331 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 Du-~w* diff --git a/pom.xml b/pom.xml index 7f96043f5..79bb7e533 100644 --- a/pom.xml +++ b/pom.xml @@ -462,6 +462,7 @@ java-design-patterns singleton factory-method + abstract-factory From a1a40880873bc40f977a3cef7d5b9f45c70c9312 Mon Sep 17 00:00:00 2001 From: "mahendran.mookkiah" Date: Sun, 13 Aug 2017 10:19:48 -0400 Subject: [PATCH 329/492] =?UTF-8?q?As=20getAll=20method=20returns=20a=20St?= =?UTF-8?q?ream,=20we=20cannot=20close=20the=20involved=20resources=20(Con?= =?UTF-8?q?nection,=20Statement=20and=20resultSet)=20until=20the=20stream?= =?UTF-8?q?=20is=20closed=20by=20the=20consumer.=20So=20try-with-resources?= =?UTF-8?q?=20is=20not=20an=20option=20as=20per=20sonarqube=E2=80=99s=20re?= =?UTF-8?q?commendation.=20But=20it=20is=20still=20recommended=20to=20clos?= =?UTF-8?q?e=20statement=20and=20result=20set.=20When=20connection=20pool?= =?UTF-8?q?=20used,=20connection=20is=20not=20closed=20when=20close()=20ca?= =?UTF-8?q?lled.=20It=20is=20just=20returned=20to=20the=20pool.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using //NOSONAR to avoid false blocker issue. --- dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java b/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java index c5dc7da3f..6e93207cc 100644 --- a/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java +++ b/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java @@ -65,8 +65,8 @@ public class DbCustomerDao implements CustomerDao { Connection connection; try { connection = getConnection(); - PreparedStatement statement = connection.prepareStatement("SELECT * FROM CUSTOMERS"); - ResultSet resultSet = statement.executeQuery(); + PreparedStatement statement = connection.prepareStatement("SELECT * FROM CUSTOMERS"); //NOSONAR + ResultSet resultSet = statement.executeQuery(); //NOSONAR return StreamSupport.stream(new Spliterators.AbstractSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { @@ -82,7 +82,7 @@ public class DbCustomerDao implements CustomerDao { throw new RuntimeException(e); } } - }, false).onClose(() -> mutedClose(connection)); + }, false).onClose(() -> mutedClose(connection, statement, resultSet)); } catch (SQLException e) { throw new Exception(e.getMessage(), e); } @@ -92,8 +92,10 @@ public class DbCustomerDao implements CustomerDao { return dataSource.getConnection(); } - private void mutedClose(Connection connection) { + private void mutedClose(Connection connection, PreparedStatement statement, ResultSet resultSet) { try { + resultSet.close(); + statement.close(); connection.close(); } catch (SQLException e) { e.printStackTrace(); From f6c8bfbc3950474999ada3488c60d09d0dba2216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 13 Aug 2017 17:34:05 +0300 Subject: [PATCH 330/492] #590 Add explanation for Builder --- builder/README.md | 98 ++++++++++++++++++++- builder/etc/builder.png | Bin 53747 -> 0 bytes builder/etc/builder.ucls | 162 ----------------------------------- builder/etc/builder.urm.puml | 100 --------------------- builder/etc/builder_1.png | Bin 106529 -> 0 bytes pom.xml | 1 + 6 files changed, 98 insertions(+), 263 deletions(-) delete mode 100644 builder/etc/builder.png delete mode 100644 builder/etc/builder.ucls delete mode 100644 builder/etc/builder.urm.puml delete mode 100644 builder/etc/builder_1.png diff --git a/builder/README.md b/builder/README.md index 335862676..d255ec2f6 100644 --- a/builder/README.md +++ b/builder/README.md @@ -16,7 +16,103 @@ Separate the construction of a complex object from its representation so that the same construction process can create different representations. -![alt text](./etc/builder_1.png "Builder") +## Explanation + +Real world example + +> Imagine a character generator for a role playing game. The easiest option is to let computer create the character for you. But if you want to select the character details like profession, gender, hair color etc. the character generation becomes a step-by-step process that completes when all the selections are ready. + +In plain words + +> Allows you to create different flavors of an object while avoiding constructor pollution. Useful when there could be several flavors of an object. Or when there are a lot of steps involved in creation of an object. + +Wikipedia says + +> The builder pattern is an object creation software design pattern with the intentions of finding a solution to the telescoping constructor anti-pattern. + +Having said that let me add a bit about what telescoping constructor anti-pattern is. At one point or the other we have all seen a constructor like below: + +``` +public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) { +} +``` + +As you can see the number of constructor parameters can quickly get out of hand and it might become difficult to understand the arrangement of parameters. Plus this parameter list could keep on growing if you would want to add more options in future. This is called telescoping constructor anti-pattern. + +**Programmatic Example** + +The sane alternative is to use the Builder pattern. First of all we have our hero that we want to create + +``` +public final class Hero { + private final Profession profession; + private final String name; + private final HairType hairType; + private final HairColor hairColor; + private final Armor armor; + private final Weapon weapon; + + private Hero(Builder builder) { + this.profession = builder.profession; + this.name = builder.name; + this.hairColor = builder.hairColor; + this.hairType = builder.hairType; + this.weapon = builder.weapon; + this.armor = builder.armor; + } +} +``` + +And then we have the builder + +``` + public static class Builder { + private final Profession profession; + private final String name; + private HairType hairType; + private HairColor hairColor; + private Armor armor; + private Weapon weapon; + + public Builder(Profession profession, String name) { + if (profession == null || name == null) { + throw new IllegalArgumentException("profession and name can not be null"); + } + this.profession = profession; + this.name = name; + } + + public Builder withHairType(HairType hairType) { + this.hairType = hairType; + return this; + } + + public Builder withHairColor(HairColor hairColor) { + this.hairColor = hairColor; + return this; + } + + public Builder withArmor(Armor armor) { + this.armor = armor; + return this; + } + + public Builder withWeapon(Weapon weapon) { + this.weapon = weapon; + return this; + } + + public Hero build() { + return new Hero(this); + } + } +``` + +And then it can be used as: + +``` +Hero mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build(); +``` ## Applicability Use the Builder pattern when diff --git a/builder/etc/builder.png b/builder/etc/builder.png deleted file mode 100644 index a0280ba53f7d29a15f93436403cd4d48e9c4bcf3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53747 zcmb@ubzGF)w>Ca1g0!HNARW@uNFxYH3rdH;&?N|iG)PGa4Bbd0J-{F(N)IWLLrT|> z()qjLdDQ27&iDMzdC&X$2OpT(_ul*7d#!6->)Lx6tg0-Fi**kR1Onkcm6KKjfo^nz zK-WiaT?am4bVC6@`)i*{OFn;-f@(0bq1W^peVW4Y)q_BST99Jh?`4~LsW685r}P8Eb7O29}bwZ1Js zdu#034QuJ*vzCC*uT0)Z2}w46@%dWhOCi2v@WS~;!$-Fl`jh%Ydj>I##nzLoD2z1zW+`1IsoZY}47KstV4-G2R~9hFf_0lhvM*fj~wtB;iN5^8I?5i?h1x!<*6&F~?IJHm&! z4nir!XjSXLn7SoBld47+D}1u>Ac`quJOX?}g7#{<%v!LMkb*&r97xcFrq(C-upGFt zuDp9_bCHO{Zo)fodrow8+5=dHH{pUZXJCDb1ne3$x)2M5j3*Y%szO-6^C*0r%q1}9gz26fzYoE;XV*ZLZCi?vR~olVBgdeN z%5^hhB5q+G@R$YK)o4L7i#q=n66*!!BMxpP=po0|{J3%%g;90;aDm6=-mkpt#zn?A zgg)MPS6tS9%a7V1+m-fuprk+bREZx1#=1`g?AC6i4HMLyWc$S^%Pj{q9oVRy`gbSy zWurz7`VCU%qC3YY>&&MflGRj&BEdFOQ`b6EyE(3dw56_gGL_z4^{@hhwp0nXtgL2` zC6N)^O86AbN|F`)=;<-?NjK*24Ksm)@7($Gryuyv2ViZ&eBNULW+cZ?fc3lO|L!aG zdx-Om1GmPbaE0`f=7sc&hJYY@5f*rBT9dA+@o(cxa+KR2vOoLqYAsgWYZX~NoN{|S zz1GbDg-=f*%*RD2IF&@=tCwknmpEZ5BHT`a6 zC*J$aZ^8bQhskScy5xL+&5&^0y42$t#T@14I~epc*o98^(<+5qk+a9{kAg+W%qAk? zUwTu~7d5)%}DrkwI~|M9>T=ozwD_M(4rDc#dry*}>3i62E{#uL^fr!aU--Fe7@v5joNft>8@hqrj}YF~GnC>P_idm$7!{+UZQ2HKTLf4{N zJ^D9}H~wYUY5C7lZA^`)$iDNhByo*LeT}E)BWaB%&_iZ;<5uTf`q9`@Ys2@ie&!_4 z!c0-|7Oa$AUt~cKu&&G|Mgpc{+jpK=>aicS-p=81wvAmX!r>KSTh3%LN|lq+#F^1M zBN;g(&8L2NO@ihM9daq4o>n8_r>i}jJ&k3Dp^X=7vrG1soKIiSw%q=+f%0@nX^lUB zM%vKc{S7ea2*$_%PrquDL%@eEDoHGM`C+2AtIPa(Nt4^;6P5zsQ_X4rj1(4w%C9GO zf>%OCe=q|^L3;0M6%^%R)ye93=Ho#hMAMwGMnuN#I3Kx_ulHJNj%j@S$SpN79oIcH zHYZjpXl`;=)>skYnc!T12JUoU7Y)xbld>ygNA~1w8O_ACn8GGqzK9jGBBQFG?A6Qh zgRYj$j26m%RI>KzvC7FRO1m_xrpH!OWnn$TFc*r7z#BJD&AUyWhE^vW&{aFOF0O&v z<)=LuQ^HzEZY_+=7J)N#y5HFJaW}Ki8!}rdP5`Ho|Mq*u$1oy3!nEE_8EbPGz9?t> z>#3>z+fdsjpZg!G@65+lbmoQg%hb~(s|dzJ zgVF#^-hHj3Cj4(+M`PlkXRsAxIah4 zy)S1i(`T*fO3jKz5)k1nhDC4U%0seW=?y_=tYLmPc%y7UxBkNWbu*Huk*F3l_}n+R zTB$%*$b^gbv_`{R4ni~qQ|8!@vH76w9Zb0Hoi|yAMX=EQjUMyN6n%Ojjyni+5Y?{@ z#x%M9d(o(o(hq(^0xnd^|Ns1}p55Iubr9jKO6GE-Jc#r!VxkU)1;12`0>-&^HSGV- zI5>33ysCEi#Y(I=F%3UTmc-s)dhw5;210E}%4~0mXGQs-%_tL&&Zo>CFZbc%Tu5lVK45KxS9a4QfjH;v z6Jx@=BW~NLA!j?S&R!0g*OKSa6;8F)4JBU-N>dabA0|7!K~W`o7kxsUn?{5Ve+-_2 zfG3ZPEck#~$Js@+JDurvjA~PFuD@H?*A2U%_k=d_og>|Bf zZPFa`%4`kSJZDPGe#3WCOd=|4O~9C5mw!wG3(3#`?#hlwWvDRmF{@Rs+hM$3y5IRE zMyu?UsCWzdEdAmaXP3z!r6otrCsAKvuAq`ILz%&Sq0{12la9G4P;(ER}RZP9Z#(T0{3u<&b&|L^FN516V%psAt_w;bwP zZ7H5v?j>kP9#`8ezE$Q4@88hEx3`N&<+%Rw3r2b*?C1%5SzU~dOm%Xzh4nB^TEny> zO-qj*)>pp8oTEQYp$sQG8{v%=+pOuQBVEQOY|aXCr~&1=501n0KNUreEp3)^%a$xU zk)!d97{3=7K$@TSBA(ljpX(8Zbw@L}%$Q1W{p}+aG8R4O+wUPrCap@ z=%+iD5N;(GQd!m(IS3!Nly(WsF?6u6^BhL5g;ZH&r >6^@T4=dor1yBM13Kd$O z?&r7|elDvxUYugJo46~`+WW&O4qM3B)51NuVSUN2I90jU(K-YyD2_s;LIyVR)4rYNp_O+xbLK=*aZ=Coh+|fI4#HIX!D_ z6b=QyV05uscMPMDbgd>)r_MVITbYmbb;o3~@ivnN|Lnqs0KY2T<8X*c=b*&Ub17u> zwg6o_PCfz;Yubn9W~^r}i=KwK!Vj9xR76164F+L-B{;#=vfsX1c6vGZyS$D1WyKjL z{=xRcicmH_q5#|}N(G8MLbXZx_0U8LDUG2Y72roVWm}}BG*TTQ1awyupuBpAr*SBw z$MIFqcS67Z1jp0Ut2ersY`dSD)Gy!`V|kfuO+_6{+$#=vmxVM>;=0%hK839vcr;GbPYtgsIrvGB}~Av z@}&$w;9thQvNb~blT&gP!}>{&lerN)uQyUQ?~+5Bk1baU3Kre!W=ul^>V@7kt;U%+ ziF&VBl3!cjaO0=om?|Ue?tvdjkAIJLd%FCCXP=4zyK-}2GFP*RHm4+(v(x&ONddA< zg|c!BUPr95^_J#1FyRktWK@Q6Hk|APqz(xj7&y%3eqx58<5vt0Z_Aml$hz0fA#$n) z5LB|E zRaNXEW9V^0!%!AGGX|+-9Irl#1j|BLrXw?R$Pnlc7=D>QhC%Jt==zX?OIrCH?2y?m zBz1?&YfP}Ho*NT-_RM<s+^w-N{Eb?do5-NZF)VvxlboHlv%vOkH0*D&*Oe)s3a3>bL?WPfZa*_=w;qG7lkk+(WAj~PGei)3q$8`?Ar_duos8e!q z*rEILN#Yy0=V0OYG{>d2Q4K*S6#STsq5VZK$1Jj5p=?yD|Hn1x{eyqmTWwfSa7W6( z6WI_~*lXPNsmPc=#@hz9smXo(Y+COPj=?t9+_y8_r$m2ZZnxt8hq`-RF>%`CUfkn4 zN@kBOZF;67dH*~QVGqGW5+1B|AUCu+13^QXP*Dg ztGHkm1A6uX^{7oqh2bqD_w46%M)xC&J`O()p6Va>buZ>KjY|qIV2&+yN#58l;TjhZ zUT;G}+?iiBSzs5JMeKI*pFZhtO+48tw(N?s@nLyAnzX*`SCCCreFn=#f=qvpB1eyYN6VT{P)4;l zZ|B^H^&q;XlUT=$!on~8i?T%?9=j~;8VlyHaONA&Ap&vV19CXjCpNE;WaB&!#fOQj z@B%#of7!Y+jLLiM=(PZ+ zfw%qK@nks3hTXgH*TtsgJg-K7C_+-g+DOf*=L)+qn3$lcE0RE8zDGZ_d?}S-*fx)# zxT;Tog+p3OEAgYPLY2x5{l?>7B7hjkyeCtQE{1$Vn~SmHFPia@D*PzAXW-sI&|O-m zdELNzPA4IkQMWM;@ZQ+JycZM7KKl=+LD2$E!y@p!?+4BtxnP~#MH#bo$~64BH&o+A zDzg~4keb*_b!?;+o2b9gvh8PwzCRn@PLs+%ahC z_%o+VhDVKOo$o-9kT`Deic3;0$UQ{zjv4tDq0Ap8_Fp5FI|8mjg1=l^&)xebQ0UEy z?7Cr-;GZu4ty?WF#RwHCgyv}-3ofvi(Y}z@!k{Pr7(0O*r}E}N$GU}$k9^-Unj~R2 zz2AAbY(aKouh+&j#&lpWK6H~m?|7&9L;)byo%p|O^?Mzs;i$If>rEm7JHS%Sw;qa< ztg)S0*qy_ks(LXr6^A>daK>_{J4)kdkJRhN?1r;T;7y&Xoy>7BzzD<)-{$K{%Snb3YWj13xl&CM?N`-k^4spEHf_Fb zhnOgTbn89BNE;ulE7cotbFUvc*b$Qk4NgmB!W^OLfI~7<%`tr}e#P^7hHWzvdjHLv zdOgNL9klrucCnrwI}I!c_jO>{-k5Uy5;y9U#=fgjj>S+mkcGjeuBV0f)diVoYSmKX8u^9A%^nBnea-0N z?LS=!LtI=)NJz}h%!Y@D3F&oP)Ljgma<}e~ubP}9pTs5k;@G{~z;36;=;QbM4Vnigwxlj`hC5<{P)6BQ&Z>W<}?ap z0mt&^EexFDdXt7y`;{E{%o512=ak^%;q4zB#K*_C_Qb}KKF2|SUNMb`%h#&K^*^8iB@Xr-V2${oMVk4{e?sEyRs)#YuF%J#vt z@c-#+9jVdLcS`YEqAbl-vjp0>X3GC5bw7eNHa5awv?IP9e)oWvK~KB(4>gY3eSXln za7ai@Ebicq-@O5!e@Nz$3=IZ-PoKLNSevWPp-?tXswVeBVr;C38z+|Nx0f)Z;@z0@ zxn$7(PNsZtURf1cSB*_fOcd)@xAdsHtIjnwJ#NZq<5iS{5v>u7VYBkb=Rzl4CgdK? z?Sb!^$o#?>QfyA=1{e&OskasO!SHY#Pk#BpN|@{Uzl2bSwMg@7(ofvqOC|-Q+7f;T zc$t~yWx0gP_*#fn(ZT*c#f*Wzz7kJ97cM5$^E^C{bIR`X*|xQScs&h3dq_pAEK76| zKT0aR>yU;Y+8`R63C!a0HpRv!dEs?E%+r3wt%h+)xJ$keNX>exx2{{s`c{Q|EaePO z2NCso)21&|s;WsywK-r;ikIdT*qn$Q zwkcgQN=h?CQ>$|t)mun1btqMp)QKnCKjynk!$gn1%UXJ<8(e%rPPXviS6$o=kTwV;=clu zA7x(?Z3O01S0y8@NT`@yDNdxZ5NTQ_f6jA^{ME37@JtIDw58`g_R-`>4-ZvO5J85X zna-QXLoOxna2gM3! z;NmiZT*0-9F(*i*N2ni)Ixjsj#}Y69Al8-+HbGE{E%$K{=3Bzq_3oKI2%^hvcD3#H zr(EUn$WGD+L&Lck|Bkm3Lk_%dUS47`wfiZ;jgsM(azMUFE2D)SUilMzN9}LR_F4VQ z`(`bis>k>CH#aui7HE6N!f$fNfti#SKFDV4ZAWeWQsJKCm0r)*D6G<9SIJtC3^%Be zn+Z!qK;+B)Vrkr-h$q?>V@ur=e(|estn%vWrJRxltjJ7szFe9*M}kcHUzXC@x4rF9 zIP`JIYR^qyS)W7PIzu~NM84|O%>THl8ShHv*%LI@n< z1A+b@x+3s6VHQ1SBwFiwHCQH7Gb)cW-K<2%Q`CPUL4||bNPn;-&>=AIC16<-BEbsQ zR5}&sPb*fm2Q&rZ>7}ZMRb$SaX}Mks*|LwPX#RSX&LPg^d2R`?aPIEzPpTfWUMWJj z=GxBXTyeDs>@W;sau?LF%fw@i_Z0OHv%PG4Ise{FAER42`*9{XvEFZ761o39awxSL z#d(hLj*R1SVz6Zod>vK=fMW@?Hgz6##%Cj*8*s4bM~U%8;h-Lo3?t5b=ysoxaAHdRcsJ+Jn|Go91foz)B!%}T*+sqf^x0j z-LlZ0c~>TrCdZD{sR9!Bd=Y?yeY?r&T&%Y`!Fn$^$)zSZ`o9#QLToZ1O@zocZKP={ zSyB&!WyGq8nq?3lUzOf8ibO&-P?M#r)PzA-Ke|{m8Az5o0oB^)?RK1mW^PHB=#_c> z=d|E6zZPdd)e;F?-_s7`y%AyCH-So<9b+qjRZXEveH^o8pSF4($)Mx zlJO!4kO%^1aCLFmeJN|JTL2e}yvz}NUq5MIOjB?B;R@Tce(m)O6BxteYc)z*AJ}ys z5D&_PlPbU#Xd{EWIpUMc@U*s{b@4C#%CcWNqBb@dvr8J1Y!(_~O|LR;Ir&fTjWeTs z%l4y@K|7yhCjWS?&&2lXNAhqPUT4o$Jgeu!V5xthFY_H68ymB;#(Mfybkm)QWnXXn zgMh$f4}r)%g+vBZep}lUIl^O~y+!kn!$WF?dSp>-fwik@mfB|;tbf1@*k{YqXb3Za z3df3q>>t-XuE<19O#$2KOVzoAc~0cH8r!}V@A!@PRL%`V-foejc?qftiocSJhgb$? zLLAQQ{wJNWtUy=k5h+Xhs_t~!Af)1lVDS)Z?N_q5T!yUXQTB^x8!FsriBer<)? zOisxa)ic-y+23zJI&wwlGn0D@PWPT$39U}H_dXr#!MDGRZ?Ak7a_ttL2voKYXfqq7 zY-w3zCgkK+Sr?EyO~dO(!#BT8nIx}mxN*#CgMIfsYsYsf1ry_9fF-;-Gm;>DF9Z-c z(`Qw4(-jpJI9A<$|3(Vndd`VaKe=loT-H)sW%vx8U3?h+0x>9BSY+7vS&rFa14tWX)9}gH?SbZ$G2$>Ma)K|Bap&7KvfM}aC9BQG}UHB@b3g_ z69!@GREHYyQ>{5PeQlO?JKaZf%N5cgWf)H(cI?b!5rFrt0;!RYnB%HY$*P}Zcr??0 zEf8qHViQqv?~w=nQG*((;_t)sp3Cinb<`@U0B0KlbX-+ue^z0I45sW7vOz6s%o|ix z|4||cjEGu$Fvy48eC*_=AgMsX zEk(j+dR>n7TPk-2U$(YCt!g>^n-{8j`K!23O{_T0;{E(63#4*ngZcP@PvN?t`|R>7 zfVw>dW{hcjZymhyw?SugqfjW`t4s#XejlBWQ8Pl~87UJ|dg@mLf7Iq?X-SDt!P?~H zq<=H%V7~Z2_{hS{{QUfIv2L$LYjJV0KNNrSAv)h`-$SV9F;8mH#rbib_i3T{!TI!Q zP}4t7L}RXTGBwoKr##f@XYExM!>Ocg0QWVXSid*0KN}Kgm6_p?oByRJ8$rSsuRoZPq!mgYIv4Aq}oTJKo)Oa#S888x(vcZ}Tk?$oODsHO75g zGktfU>xi=|$6U1@tW3SIwur&kCZRzB)z~qMMt@T{pQmqleCgSIH_93tIZwwgmzjZ| z^sCkaZH*jUc+Qyvdf($s=TUKc3@TV@GWFTt+~wg7Cg)T$#@nSn^vEVjs+LkqYinzO zt9p5P85tS9eyv_|N@o4T1P{7iIw^P!q0HQAq5vTXReewSHzZZIXkH~wC^TyL7CBq&38z!>mdTx;45tO<3+X^#Clvjm%R9k^9D=ub7 z=S%8BAf6U$=<4Wt0{VU>j4ctO=U@bR9BZ1oCO!~WkUDnTNY`aZr^neyX< zl47Qd9Hjh}+WCG-t>v7JPoD|J*!fFF1u=lZx9gOlDDN%ri=L6skji?G%F`zV z#wS_cs#G#CI=`E-9OT5qMm$KmRFR&a@1cnIp5}llcMuD)NC2GHj`yCWRl$7%5?Sv2 za>aM7tVahMioJ&coF0;5ZBHB8H2tu_)G8ajnT={#zlU-$^S(^7{)O`0UV>RJ9nst!SvOW;*9@p$a}6!ajoRZ=z7| zSj*869Q3EIu&%q^(YRL^20K#E&dva#CWc1~5D|plP1_f1+%ab7_c!Vq(Qj%bAtn|( zTTuxWC!M4pH{33l{u&YiihShs+^2p^ZRBybPH|j)pkdQj9IK+cy1Kd%B0C-CVm}j? zpCgz0(l1(=#2kbsLL%;jz!)lu11!UynxxYrL4iPo=}0pujTdw7kq>_%qo>r<+j~B* zat_WLaNtJH8r!(IXzJMoH)1W3;xZ&Z_@&u`1HaLkzrAH7cjGdEN(k6PqI@x=m>tZv z$ET-B$Y&obbPVk7Rvs2ca#sI?5^+mBh*FmW^b%-2+Ht}9>{QbG8|Eawgmdgd(Kvqy z(wAk5`}bW7)_4O3(?ap}1_|2D>Mcm zLHqghXTZf%!HT41cwl}-lWBi(!tGhjhXMjj=aeCKw?Om2?cGTK=n&=f+Bo$|V1(PV zeNRc@cngPaxz7NLd*dBq*E+xKBm^X$PpYqjb^x(Vl`dvX;YnUOEue!5rb&ip%pV@U zv9q&#dGiA88&A0BDhHjR6Dwl~PmoD}F~~;`z?tiBUJTBrdnP>x5|(m%^0{Ls|KsR6q7jJKEDjj*s7=y6<5JiXj9dYLkO0r*kSJg2_qmmM>3!RFk}% zOuB#0;W)APyqiwyr_V$UrOO(M_qMrcOE^O8Zi2x0P}~>h-rm!?*F{Z&E-+glsk znqF_c7FZ<2vR9`(qrdBw_TQqgehf5OnA@j{^%}{T9%Qy+~Sad!PHnxZP z1ZtTtF#UTiZN8qK)-w|E-H|C2Cj@l>ms?rdr>4>X2z%th=XcMD*NGgF_xheLb;%oN zQc|5;dv2*8d3>P0V5t{^Vq%au36hI$wcL_a8<*o31J}T{lXhAC-uwF>UuA97Xga~qE?8sc_6M#DRfC%FfcF-;B~M9K2i)N;?$^q^Q|1HJo`bu^iRXv zARKHcZceL$K7MS_er~&R;yU`f%)U$>%E!lRdv5*3a+zvfqAUcPK8N++j|$O2q`LK5Kk*^0MZTj>F# z*zULLC&ND*7|lDzC1gjlC7DC>ApqLp0JgT9NpWv5!TuzJ8?a%T&?nWjVFc=PT;Zuw zg+n^p+RU{?pvY@-{G?%9E3BF&mk&f3tJ2N;rePC9gi-?n0s!kJ6`gK){8C8V$I%Du z7xkw3P5?Nsbo(XHEC?Q~r5;wC1iZ`2p4;o!uP=?T?Ir>}`nFgD9L~?f!!x)gou}bG zDtj$kcHE{MjvHz$t<=@>%{zkygoB1a=h=dOdmKLyfwj8lW>Cy;5=_nHr0XQp7Q?%5 zSrzXdMk`j@(w>^;{Tvhtm|UgI>43hrc4Ar@B?~6|Igcw3*jf+^x6}Xd4w1K+n+DZn zt+TbOYt6Doc1|ZSsSk4Zzc@wOd?PSl#h>AL924|09g^*lPX@atvk1tgr?IP#er9P$ ze=VOdxm)4o2f7VRyVm?gaEo{Ps0{z9%4GDmDVzueMaxgVD&A(s(cItY+ z$LB{C-$(PZZRWU)tCT^iZ^2Srf(6$0Ut4$mmKQL%^9isde-c>ECaGH_YHOyo=@Tgu zipCS%^zo%eKD4ZzEQznBw6e)mFA)_M?g9qBeWuw!3};EHTGqe`S{z|-ZF2Gg1-=D0 z`@agwYi$fUIy(BG2H>hDV)hv@fu??MTN0@N#h*LLO$1bFvqIU+8lW$)sF9JvfUa(^ zy{j6XimCs}aUlfo=bRrIuiP5aK8+4c7%C~6q{AlWsKdw+SfD&P{`sKzS|G4C6WY-6YTu9g7(P5YqP1qeldeSr>Y(i@keojuFgU z2bwslN|81lASP$_yRLw}jjrOM^S$l0_`DnzW?`N;0N8WZ7srSdZEbA=s@O|wRPzNl zFaJfm-^bMwb8O@^kZqxj8OvV_?0=*j=dKu01MnguG(_MBg7nSD!i$TGR#jubIZGL^ zE3hbn?^B@Y`4A<*Wdmv~QR;E-6okYZ*B;)aClCBmkV5QLUtceRIwZGOox2qs4pO9a zU|>G)4Yhm1qS%LK5-tUte$a}^?NJ3{gXH*eWDd)L{rliJrv4h3HZza_g%p0x)QyUB zYbd$+)QzUK;h>e!i~r?Tq>WtW$l4=?jEKluv8u+K`-3U8k00KoDVp6Jj%gevJd9%w z*wmrnxE@X#fvsv9X`}ih7IJHd6oR=s@FPRU%=u=;L*srjvH<`T*bW4NQ$**R`M2cw z(SZ1#6$=62Gfd`F)ol{LkNOIcZDOW1?a#FJ^(V*1SO7q{4PckpV@??bec^ZQivmDM zxM;cSe23Vy|~v(V%KMt?s$XHJ=d{@04i43~NX$9>^iICKx8OU0=+IR3ERq3c;@lqeZ*fo$iROfN_{&J7_I+hS45$+6 zy(8CGC8Bmss{0S|=15MiNl;QFU-ny7X=rG)iK}?sNQks)`X&KWr!~M{8I2-qoWcij zV<6B&i-!3+HiZr8>!^a(!V7Zj_LrP2?UoLuV{zz(8Q4n1@R*pGfbd+T0LlOaA+7Y@ zfq{XGu&RsL9k!Kwfo^=Z9=a|Clfon)Ph)h&EIKD{k2M}+~%-UiC`1!!z z-i-#OKhdu*-+j}HYx>8>PlD z;W;(x??-ZxoOPwK{&Afm*L6^1uFDDEDloo}7NkF@SGUS`G;gF}*pYTP=^~PYxM{I? zcqHWAl%N7U>P@Awvck7m)n7F??gv5|ENl~^ZECvZ>^TjsMjB~?Zi-trm@D(yOd%*# zx^&GzC=Dl5C*jdk2($TohqF>43$<8xYXBCj#r0(nRNtAKbFJIb)F1W~qQ}+tg%)@3 znrEG;O}aC8k8xK2#)AkPJf?{!0W}DB~sJ<4qS7e2$GG6>WhQvNqZ79-LQ?1bZWq0ap`o4 zLiC2I$?qc&2o#Dfc$Diy?R^Q1NYqE3^T!c1jvqg=eE=WO1-J!zj!f;#JlMzIuy;u| zAJ>*C0u~$4Jyj52JZbcGJnLI)p_E9xAd$A1GFLuV^yO3 zi82$U$xw7<7!RIDKJg%eV?Czujbnq4$M8;4x{a0+1q;hyt@)pOxnqeNep_#6QK3z) zcJXm!stBEDM4IY*&jT^YgM*7`GGW)P0T7O+WPGk)_N<&()?G1|w-Aq#oaq}QNEsN* z?VpOH&?i0mVlt~-q8G-vNWWrEQUIYw(v^Ms^r@mk-HA0Uuf>}NB;y0tOe!LF!zr(= zt*xqxU4K-_f%Gr;1xJ8hADP~)r~=)+1=ZJg{J19AV=h8`p%$~;FFk0}k`y@>Sl zyRofINkv66dE1BOEm$-DG`DkXdb)JT3Ym82FNfuYKp?~Aly&5uJ??OsN zMa4W>SQ3UQbpt_(ySUSJ+iKz()-^;42a;o#l=i2UJ$>>+-koSvO55}0=CQG{#YMCJ z;s-a{+uN&j!dZ!ZF#W)qG2J9?I8jHDY=5`?9${(1(TGFf%`%Ih3&g7D*z|Ro^P-%R zi#Mm`_>C;6k#p2yGA%(*fu1m3yHC(SnAAujhRvuGfSCjIgDkBK4CMTqdtN`uJw$-TN*$Yx0#ko1v!u5mKqr$C_f@) zWWAuN(}~W01nx-Mk{+w7dn4>1SM}IFi>(g(5AC;`=K4||MGql6X^`oYZo5(IvW?p_ zjRd93oEOI!UDJo=%BQ`J`e*ASjr6l421l8KZK7iEkmiaZyZKw1sZtSD?;|KFoR&w; z$)3VIn<*=h0T;tVFd3ezW# zzjT5xj_^O9AWBcai=XaX7A%NW0oST)_P6{-#4ifM`)bzYo|o|^KS2kJlU z>^^x9AZXjgpIyv1D?pZ4QtA(H_3(>Fq7+|pG21y+ zus39_-@EeY$b1?`Tz=Bmez7-!9U=0mhI)1n*vQ4HYU1(6pIy44QHl_c8o6mbDZzGG zO7aI6Wlc|+#)Xo%q<4^kQK+qfCmZreo1b({L?t?oF2;smUtnxUWEhlc8ll)E0EunL zxGB2VOpsmT5&eIv-&+0e>bJTOD_r#B#RrkSafRS^-tkijSVg8r;riw#$z+IH)WP>g z5D^BVgcuO)fP?uv?zIgK4FGdQ6aZUyS)s?2=DMY+Yj`?Y&3`^y>iwgk_F}*J;{1E{ zg~fJkduxMKHwTn=KyJQ#)iLVuw0zd*{MHkf?%CT5w7x+&LpDEeAbPPD)4KfXH7{=F zbIU=h5a{;lVg+8x+{Lf{lJ>KUF;&uC{lkqJohri417px=2f5!HS!OlhlO2xfqfXS*w{Z8#BG?j*^ds+oOZV0X8#^r2aothf2 zug56Df>))Lp$&C);}*O-f)$I3W?#p!n#i#uAIU*3liM`lRP~hPt@cnpHPZh>R5W<{ zDm!`o0zyDc-0f~61-7N`M30UD{-!*qrZXSWlm>>sP?C$RV@zzxpSt<*1 zypAZry2-H-i%_%u3v?5k^}LSCVX*I3RX}1d@f3KxiT)C~5h6vGE#~QwFVdzCmzOOd zkT~SS9f|rvAn|_U4dMpk0a~lFbR%W=2 z0~F7dl@%_PzgZwg_d+}?(Z$+zAjhvGRP_4L-c1f%)CrVPhAOS2CMGD>?k-~3bACCb zMlR$<22e_|ad2#)P+_mp0ggA^8My($3q-h#59+5>M>bGnn&$ukN9Ux(^@ zVQDXONtccQMo+$k!>F(idEGe!FuBV1XyutC^YL{CbNj5xN9*$AJIKsnBW;6|acGT> z`@|B_l1&lSzRP|&e#QIhbVb+FhCHBlr~?U9SP}EpxB!Tjz>2E-eKI$#fz>0 zp-HrnH5gyR?!#fCfzbo-rf}4WX>~ zQW(#cbeNLr~8O4X+sd&jg3&_MwBA=Xgfu1M~uDr4ryR(3z?RQ8- z$AG2^bT0^yIVIo{e_@M6ajPE!EVqs9qbUr0C-yynYk33ru%0wW`_8~YQeWGhEc=ZB ztC<52M_naGOkeu@`@6dp0sbUD>sc~nl@#{#+BYh(T!qj;!*%B?4XB?o^ePh*CDTeZ z=U(PvXY)DV;?mdQJvFdTvAJ^z7_OragU25L8bY{C*0RR)>z-zTH@{KP*QHp%zL~^C z$y(D~LQoLcS_>!l#^rolE=aaDcs7V%Qp-Ue_3x86L^XbYa>X6fNbe1I#1a)R2HpHd zeAz?Y;1)p40K#|+KPBz6H`W)4mUO#C;FhUcute zJ>V)2<&5uNuoMmMjx{xU&{C&gI&!oMqQ;}I^S4OrBC~x(cm)PXYV`5={UC zeR8Rh4AMXM;$)N0ElCk##iH;tmD1DlTjfULwQmM!S;$@G;LDPkRHj~Ijt_f1P9I(m zmoag10mM$wGQi0BcQ4>hmEG;CQ1)G+!{u3}(0m(eWVGy0X(@!DkkH4GwOR9i+-u)} zY1o8`c(%8Y+8X;mW2k%6PRl|mw?7X|2D7;u10)}bf_<2I9Pz9-3-pWo!meT9|qsbs|K#BLH5r`X)|Cu*1XyE*~UuRUKnek6H;SA^;u-n>P(utdwOt% zx1&EKqU_X(t#v=8CU-cQ(&8gN8%G~mcC~bN$`=j+N&(Shz3+o-d%#&kCi(RY0y#** z!v%$Tf<;2tc6HJiy8&(Re1{Z_FFjZNPFQ{_E1BN; zwGJRSNG<`vfr5gfySEo_FVYu!W|-!wOu^_imUds{3-Q3`JRRfpj`A2YI7Db1P7GAn zpJ06YAJk>qO3c$B2OD#J``-jSe9T8Jp)CpP^3z^ZS5#5KcNTr93TvPz5{ZdHT%`qeAd!l4KE zt_ePYb@^*gQ{&gM=yodZ_wSK&LD|V|sRK|@1DNS|1^7YOz7#a+F7p_q+OOs(-U6+R zH1MBq$QxY^P#zG+e1&)Dh`saH*9sscwN z__=l>Z9aypJ32Yhi;*HeDpL|yV*q0-_?-hu0V!P1@xLwjOhP0^$)phBNgOmZ);mzQj#k|ih#_1 z(@!&74pw^i_Bw)tVsVEx5+Ja^ac5iFV?JOPeLm2+19bLqOUd=&71+t`C-Rt=#eLAy z)g7OhU;{j%^%IR0NZS`o9w7-V(rtDCN|aZyuBZ?V(lw=G0(hD71VO7?FFg*k`6;tx zU*%Cn`d^`HF=qFK9yM^9Fgq~S0>1r4aOXW}#c-D8_RZGwcZQmvM}hQn@7K+=o8f#4^f zyUaYjQg21SsCtH!=y>zl3o0k0h$xq;~D zAoBbg{rF29eSlZx4QOj=k-ix%gR+ZOzUiU;NFfKe1J-c{NT^5FoO9WOzWag66(60y z$W~+vXFy&Fc_kiNPJOCIq9W3>v`bS11?etzkGk)z1g%$uL(G@?(Xz%Xsrt3VDcY&q zJ;;lfD;MJXCwkAxTBXp_`1?BaU|kN*`qa#vC>l*T9Im0M35abHpQ(|#+=Gt6Nr0g6 z+Q})#qx-bX8p&n$*e2^J0{XcBcs=`&1U!;fTwu*DFi{#^=xb5f3=)99rA+ zB_jsCmV_xWoaqD~N1M?$p&`UB+6GAM1*XprtCFdvZj;aE?tUW8!$BeK_Ctv#L}#Y} z^qkq)#^%wZdu|q$#XOqN-FcuBY@R1${M4~$zU@}{dwV}7Bw{^&RndknLL_T~U;AyA za5JaIUxmNpjr{L;wVu%uT75Wme7l)FJAZj0>pO#NRN_fD1GywcI=AN?3*MLwi5g&H zt;+xcXOndhF(KopJdc`sSCidKKRH|$+sp{4TwJUfn+PU-5e7wU# z*!>i`o<8h0_4zuURoKq_HJ<%sf&8;=PD2efag3s|0=GvW%yy^aMjh{|Z2Q6Q_aAHt zXNb8j>+enZ4?gm`Lw^#Y1Yatm?q0~l1Yn5)9l;OX#b&rCnN)LY?%z}qOT$dKkux#y z__Y^|VGB1hnZhPwsgb_d(HAUVgh##LGx}k2ywAEB8~(_mc_x+ab9m<~Tivq&iFuLE z)ESo{`&ZQkiaB)1p&W2}<|0r70i0*bNAp~dl!S$6dt8{dde_ZcssjW6r_1I`525$B z2UVX1ZQ81d24?Lw%ya?woijLZ%RZogcb09B;Y2&ha!aO^1%6@0=kz8a49LGaqqMynWVI_+Tm=Y z4ckSarLATdHu@+GEIZFRj5o)F?5u0+1OvC%X z=n;z;EA4}l75C?8#;6X$qOQk|rXu)|h~g>?G5McfXsrEnftrjd^@MzY$R3!TD1Mhw z>IfF!#U z%2G(u*gNZfQOLD`9fL_fF49>JWT(D7RtyRd=caU~@d-gad*xY%2TO9y)ZFnXK()84PF{b+ z+662IpgKMH>-+>i25{%J4v^k6#bg~vu@Z3>AXn07&Dgx}$ zD>GxX>GRp-;6^c)069Vo4AUYFVrUXmmy)ycEtxqk>t?L+UmscC?2>q#C;{}T2n3u_ z;6UX6qwA~Vs_MF}4HS_ErMo4hJEc1$rQ-n7-6bI1-Jnv^aF8zP?mVP)gLK2U^m*@n zzgz$EW1qcZ?>XlhbBwXIwZj{*0Yn=yK-usYn=$nm3T=<(Eupb{i%|GH)(Xd1bBp=& z@8<@nb{AxS%JDi#(xu23n%J`62FLMS8E^?tdO1SId`h_a`Mo?niyIOD0=`;402%FQ zkPh(^2wn=lH0|c((C3k?mWubTzyJJf=1+eG#7)dnF$0M7!?rmA;5C5GTrR;n>g3}; zzlV)Nb({6CR5En?*|tyHTNC=XjiLrx>f%AD7DhDd;LL)d#yunhg)fCdh8>wNEXW)o@^Hi3%ur&Ec;mUqAd;uXN5U7Vdk{SBx8mXHZgpg7{| z%gR$?Vq%cM=nnh%4($rj0&HzP1Z?*$UUY4Yj4qzqr3r}JAfqN zW}@-AH!aT3Ymb(EdIXX&fGe(Pm|juL;n1>(`OJSQ{kIAS^5vtrRJEWLP#&r<*8W39 z1Ao{e{1ydq6^=$1sHv$@ccdc`dW|8gs1|L>N^=CJx6)i8_rLfoJV)L7fp1MUSxU2I z!@IHhB2mRme_?m;$MKhgOyBogM3#d3ytZXkIDPNO-Jb+>{L#BQYgiO$aEhf3SI^1# zVxA8Uw_1dFt$iJ0KzdQcrByHE*W)G}aq43XLSy6F2pw|M&KBpR#fAy(SYRS%1P%zF zhPM$C`1ENct8rCK?e78EaB^~T>;8XoVu5PT{cEmbgt*`#eyI_P$4vZ1bns*^7itVN zbL!~a`PV?Jd&o?2oeRIdl_a%G$3%-}xo%7xek6xh4OU>O!xIJc>DgNKos155@dv{< z_t-gT*A%_y3KnGq+l@v~@j)d9zi~Vs2cRDJrlElZeURb7kWB8aYj_0(i5G~eVHf<< zweE*IRj8$B*&cErL$nK+HYnA&0UmqTa^1!&U^;aBarXGRy6IC?BrKxuRjP}`Y} zg~@>Y{Mg{KA0G1^bnpvLzd}dEZfM-z|J1S5mb}uXvFydA!oj7-NotUL1M_7wS22j2 zpO*P?GdcNnqD&7)wkln{8Q@-RE7}{GPOUP5E*Dp10VQ|olyPRdd3)n%2)4prDZniq z$rvz(92_daQ4r~Itkt7jJ@A^^?2R*H$@~D~2+jt{fi+U^*Fl~_!TOytEd{&&v;mFn-zvj8h9N9(dQGmwdVgwr&thXbkF5w!TR7DA;kWObJBY>a(~nQ&QHDCEUr6GbWvp0}h>q0GHCM;F8^aD@^mBlS8%v5BA_6%q1(U zY~nqJKAL28v&!ugFA(*utOgrWk|6ndY`lY^3~vq-lH?Eu!Z-({R7Qd9`6MrtJRu*i z8dl(4N4iF7zk>h8dvV|7xZQ|MtG9H+QRJDurzamPt8(k;=JQsT=r0U^e%Z6PVx+ID z&J-FqO+BpmIQR9?4I(pD&#tXP1)*-g;&fi2>CliEG<#PqkLzn!>>vw4oatYZDwv(5 zpIEApLbRn^NaSr19_TaztaNek{|n_L5N_$}Dj}Djj3sd$MRQCF%fpE!UdodeLh^t# z5XusZjM2yb@f~OK%jaxxy;Je#08;#?^T9j!zbPw!JsyL;alRAsnLFZ>$j_;Nva4&F zpK#`QfutgIq2E$0T+09PkILHpZEuQ73vTH^z@(sknTyG;aUoHzk@C~FSu6S629EL^ zA8B1IYR929Dz`HJ(^wHk!E4n|7tZW|iO9+G6b&nSwy&Q}b6kV-2!*?ZasJCk{O_Rb z0e$`Bzi`U_*GSHYu&86scD=o5du2a?z7QlzAWu~se*QO%zpGSFD~jhv;VZa!)#sr) z{V0|5?3Db>FGgzcJgUY!O}_ofX1LcF+RLvBv6c@%rcTb6>U|@6m7pnm-_Vl#hhGSb z1wIP!hwMrkgDwDR)Na)OBC0a*sFeHu*C#XkKwBX+VNa5S&5GIIqQVzmS{L86bh+5- zl%mhW*eH_GWwfxs`H!+&JWtTnKJLlCif_($ZnHDk!H^_`BQyF%H)zha$YcJG&tgl+ zA#wz3?|c3?l~n;$igcP zsQ;so#^o7E9s0(wUO5*tJ8wt98{J8e3`2hX`uh)?;8R<}v@^?{;8;SXnVBSltX_HV zU2)*N$SFYFJ9KUtO=M@q3g}(f;n#pw1GvRka=s|P-Ac$Qiuf80bnSqh!q@XS)Rt?} z-Nmz_Lv3_$oLebZWOpWKL6^|pe}~tb7~8yHV(8ALI6F67SC7Z3`Sm0^wnRjEp|Zdn zx{C4p>u6C(5?qA>t!bV}=M?!A1hp0k;M|=nD=R}o@*v2xs(21h3 zH;9K2G_w9JJzujkTl~}#+$EP=KpCtg%SHB*B8bac?@poFJp^q6XFZ$ zrIKF<(ygeR0+~K6Tyy5}O>7ipnpD3n`jsRnPfu+}kuPH;u-Vq2+JXCf?-Dg$F{p9? zZ>sW*V%ep}7?@4R(9jSNT!GoBlp|5RLWwQGzQv4S`CHqDL-G+=V_`ve=-)eQAiyj! z31Q=y6|ryYE7;p6ebD(Is^|L~GihK*Gb6rLRaGEdg5sb6^wj`JuKnsA=&8E50-!aW z%;`^9WQpJVTeM_N!t~j|8$rLtu1F$TEnYs7jbUm=^fz+u9g_;gbZou{L;B%bsq$DB zheC^7V@s*`@2Lr}mT~ZKr8$VvQ-4lIegI8*0K+n815VlB|6+~=HU2+$vNVwyfzR`0 z3A?-VI-*+*GfZasdnY3T?!+*pI??La$C?~Cdjae#<5Vw+)&oyLMgHmUKL6V+2 zPZL$7urV8#7$ zBKxa5jq$yubj@*?PX5MC(`L38!dKw_x(h+lSz1XPdKEu{6gZCC4O)?)!8G=Q>UnGl zqRJ(ut-XCL32bx8^?GH0V~)7R`J^2m7$+bR>F4`4WPY!ki&Vb8pY5)nhM5^_Ebt$| zKHu|fuUR|vUFcglCFJHgy)^JWAFo=#4E0CNwOYdVPrz7ah3l{*Q@}%0dkA?hS?wC^ z@90IArF@k$DqB4+x$YDR)$X{Pl>H~d0)J(efGS_v&+NPgU?7@5gU*CL7wqjf5wR!# zcV+4^b7syPjcwaVyn57>mt46;j`oY{&MtE<3k{b04%H<_>D`*VUZY76 zm3oZmTw5}QolFXC=5I7#&(kLb7u|#IOi$%8ZgNOp2?P1ay;;fTe#=ka2*C650FRSs zveBbIi}MVr2Pc>*L93=2gFX3w$W{%Mf0Pvcjj-gm+SFkQmZ}@48-+R3|1?eW58|Gp3|DqdX3ZNR{D4CT z8@1xqA|TV;WEydK8u>l;SI^@(*D-WTEh@5x?aYZ5dr4}T_cxxs@sNl&D$vfB6Y$1? z=iQ)pRV9EFh6lhCPyhie4hfzW`6omO8YZEwIy^AIW+6L|ZoPPZ)V;eeNym;Cezg_g)A(U>Alvme4I2sY{}(-?{D`anvH zhy8KJ_YS`QZtkH{EB_sDZUKcSy>O^?;eaFm8|&6ti6hNYM2U)8?edRKIFY z^l8ZzP7Oyo{Z|^l5bQw@7Uzgj`F0f`V34hxcG-=2}lvfPkY~D2*i)C zN}easMTOC5r@bKa3U4W{R~I3Z7n7^5=2Cwrt7<^Af~^i(i-x#RuuK>mFD0YMVGRwy z2&JyADuiUL`!bf{!VmNyzCNk3UJ%}3`+TJlA+FsT>eF{h-vd}FOd4BuGz7f@0^UCE z*Y|&~k*EeH#R@po5Nkluv$BdH(=P#;bsU^!dO#!fUl(9072VC;-?t18_`YZCCe-yD z)kLQ%e^F=e)YaIY@>#T@I)qd4%JFGpHSYd2ws4iF!s+(JFn;Cruxm^L1ThOMY5f@F zLb(bF&u~SNZ>X}BA9-${lZt>A%dfD`ufHig?2eM0otqQGunVy`E`&Aj=3ZK;ZEwUv zN~dN+G4dxVoRL z5ERirfGDUf&eEfN%dp4j?ct(rqAE5%?$+$D(`uud<5=dp%MbRK4raU49B0=tfADg~ zYSGyJUlY-Q!%|#Q!u(Xq_XRg*3ss+MxVUy%=%NbPQX~>s=TG6N_7y4TvgypU8?z6F zLoG+AopXaVg5LWZL7W|dwYWbB=%VI^3uh;v-C1=%A%w*iq7-{%WH^s@#=A5c>yNq7 z`@b@E&Y=GlKNZ6f3(hE&!?pVyfce+-YW_`)f^%k{I`jo9iw@@i{x?DwL}U zic;Iq%MRXWj}G6TkN=e3wTBFO1yieL(!0NbxQUF7Hy=u?61)$c;Q9K;KOuAeJrD3t zc8qhJN|Gs$yB^^G>vj#j|q z#Eb0(+#pIJu+9hVoES`?ykjmOSuJ;sW%veop!0KwrpWzg>5TT2Xcj@K zRaOAf`N7~A5O=$GUleJh0U_ryQ90l4=z2v8BQLw9pNvs%h>J8Vd(#|Z3q(&o^JNy;?RO^OI z=+Mri=I;h`;_-VOt$A-)VQ-dxkp2OBvWg*5f;bkYrV=0BOVj{p@QQU!u1R-kZVvPU zn6N-lH}d<>A>7rL=SShD_2Qratb8r4gCjkufNhx-pB-{X~ zU;rUQdq-I$mUuu>38f=p4B$}MxlDMH=Q)6rG8#>()$vbE_Tc8^zKJh6+16)LwUInvJ??$E1Lc4H^srF@E9vsY5n+_ z!o&OCv|&Mtu`Jo?yM0spXF-K(ZxFTObb5OLf|H6~Ke?@o{7{Hr4?Q$?ulK=Ukc$h= zgi$38FV+sQSjR}-a&_9oHUHtjQ@;c=2A)XRSVK-cjIT-+;bI6@6x1(|E+?_Yj7Ptd z;$m*((O`NKB8&J!6i~iS3qwKnE)b>ka5#~%u!zF?*A*APehJ|emao}KGrlZ4I5U_0 z%>G^^HWM5zwzthptluDek|Y1QUC>tIHwUbRm&%}FQ`5jN_)r-@_v#%*kosHu-6;mU z6n=XajX0@}j%V#VJB6&M2uuCBAp7@yuGPiJsF>b;y?_RgH4pob$AV*u-(tNyZ|}k5 zwk=A1rj7eF@nS9!i_XsU98H2lmDL$l!!_W$bPqcW(8$U2e^gyRLeB)Mk`8u%SMGsK zX0+xmdfXLkO_0EypFH=2D7-ilbaHpE2O5Rw4(8=>mpumK>~1>0Ef4^arVOcE_6k?z&iy$2>@ zdg%E7@~1^k*aG(1z6ga0Mfjk9LkMgT#3juTVBq+|nDbXck9)2-Gn-u-uFkv57H)qB{xK7ln2lY~PK9pwR}?pn(xP82 zT0i(I4^pZ_I}z^c(LXdd$W2~}43GH)`%eV^Z4y_YI7ep%GcjW1{l=%wEvba?y0TLM zzO3iG*ysc23lY+{3A<0xtt_ORdm5cO|UuoGY* z2p{!>Vor`j%h|%XYFxV7qcNlDfX+tai)xDfQmk>h#8tP}rX!vS@nL3%&wH(-ULSmd z-V;c^f*F3!#|3K_J3A#dR|ki@X-NlVD`24w420Ky{t~!0L6kzih+OF%!h{BnzHnf!KX2t$frYfsMfd%ppxZs- zzf7c0fS)utA(6Uj2tiBM?96-5SqIf5V+rZohyZVg40iPMDu|JW+A%bqP5?#L%(TjW z?K8UkwzjaM2${xT5(o$sP|@1}Kzevf{w^dYYqrZ^l9@L!#A z|M-oywzsA1-A{Osn?lK-@QYJvIq{|JVRS0mr$>)*s6hF@lcMkK?<0_cv=GhQq^qDU za!mM4l=((^?nN>wJLU=i?>8+TZcP7+d*Ld8o?_Z_QY~9fxm7GPB;=gue@bj$&fsB~ zLuD}9`zly+byB&7*6}b5(#1IQADsf@tFFHSx<~s$P=}xZB34p)C@Kn1Wu@TpL8sp$kZ9#n2@6~ES_4tUnuDPY?~bDC$R3n z7h9Q#2Fx?iMJ$|*W>P6F4i+>4n}8ZQ z-wX)p9|ty~2yKzf76lpc=hH3sXBg@k2&>v!T9`W@V(>7U7wPGWdEiN-_dLJ$8;kit z^y-dlgM0gxfn6B`nFwB5aKsTj{Y&_}0aF3x>$>wIWf3y(uPdQ`@uqJ8#{~$u!45k< z?j6F$avunV>pgJP)zIKlua!an%)*lLI%jTw%CfLLyi#4ne!VXNnyC7_>}xRqwE&%s z8=OmU0Ym{#G71VydVengaT_$DPy0m@9~~J6KzL80<8AnG9j+2^60@G7Qt(P_nfzbBIvskv}-*)oG)_p#Afqh^84;ke1CUt6~Vhh95ix-!5-}W7oPkK1HPl! zyuy)+*$rP}9@%lcSWY3vckw)mVs5Dqi4bZbXm7cyF+EYqDC~>ktYq0`t=w^2O$ph# z=J{|XaJ8YF@*#zvGkC8a36XyavezWGZ(=;jfM{w(Ss>6JoISyFOJrI1-kn$lCLbdNZ>n`xHa3imjJuk9 z^%t+vP4Z)khmAA_$vkFPsrJoI_avf-i~|Bj$!nP@lGWrWC;vHl;;Y5_t#(08k;5RDP2@c@p7EwVa?-UAR+8Fp4B-$dLE+_ z28u9q(1?sP`*^~=(C1Qj*x385-7{Atgt%FHJP!eT z8w(4%8uZ6lKXhtseQ#4=Ou2z!FEYhf(;B&P5uoe`JWo+ zK*UbQ`&~IX2*11BVQQ>PGMbZt*Z)$mJDO=>_&wM`{WCno4*;;h@mZq#GjOopQeh2G zUal>lpP#q-!&^uyjR!KP)=i~g)5_2-$@o)QEsil$6c@W4S5FN`AzzyS8;zwJn=I;h ze|CK|*lR68_;9t4vT#U2?S}1`yyJKixps`~AC{)_3f3kGUB&>WlFg8A)0Dn;7!6kcPTPU ziED|CMwObyutr|P8zi+XW;^X(PjvABTJBD=3@a{5cZIq048eq3?d`PM({lVUiWH3L zwaM)##_oMD$&gZiNLkn+g)Hn{dX;L|8y#f(|GFS4nIqGRp6NwCt1o0D9~XlkCsuo} zFI_0Id;}w?jFEz;qAR*y>1OizwikcvSpDmjS}W@U<|Ch5G??;kb9OpC<@=S)TqiX% z`Zu>(s?2b5vph20(QNaTS-jk;k6Is_n99@1wjTOwz992hEEtZVgvIU46>(NG6GQ}# zK4!(OlwTBeK5?ROV{5A1NbJ>kRvI$#Z85@!w!X$@-Qav+^+P9YQmbrm>}o7YX`6r{&*k!JPsgH#Ib#Lw(LraiHjjhW zWj5(u4cyPHSmU@BDR;u8+qD;+Ld&M&OVH~Ht}@BcsFM(-)Z80l@x#+>oN(zI}&WiUzAQB$d1)oAz}0ZGpGA53@X((`w`Rilq!e^D+&9w#oHmQ<+qj_xNR>Z>XW}YPo%h_nUg- z3`>T?$qNO&`Z$BU_}d>Y-3NE-%pc;@kG{GzIsZ1*Qyk;IU4ok1JVax|0v!cNxpN^r z4%(g@1GtIQ2EX$mu=GM~>HXm2n_(6GFVTYCx-$lh)Oj(*YGhh&>7MS>$6SRC>veA| zj3k%Rei*$YG}}9Z@TIR~O(QVl+)X251NJHwwvUh9@6=%d`fdG{Di8B>XdYUM`0jIb z0v_ueijgJ*#M=}_m)hk@EY{f8!`4(6GTvRKm?v?K8L7H6xOgbf5@|bsda4+~-Vc)| z!IM7ZvUNt0t(TK#!*SYWUY!)ain}3Fu-4;MC-uO@wJJH4 z+>?1;CZ!ebS|Bq+Y{`447lGm9I9VmK5noc~z2^lzq+#TJ4!^IG)BHT>AVm_%2qJ@$ z2CA1wSHy`w|IR^+$!oB?m&9SWK(qp);EkVf|Gf*!U0ttCbeswyfHJdEQEv9*#@f8w zDUZ{32`0M<(z{=6rL<8QGlRv-84DS257-?wnjrfL8uwGBY-o(weq(DAz$M zK1hB|wB+IXxOt37#^pFX5W~RTP63U8(|^`zsi%FfTJB6Q6vKdQ#WLkN+Mlo3j!yoI zpbKJgMeAMCmhjjk@kWE_JHdEU7fv^%J8f8}vG)9{iw<{fEdG36aOIPOU{UAPp$J%h zl*ik9dl~7?drM0QMeW)4Kx}+uZz)v<6}H34x6ePb#*E`+SsCrdSmRk_uINl7mmBFR zi8m3>=We2EPPv44*0~*0^(B{5e{51kbP>I8LL*!LpfNW)TYsw>PFi*~v1Db@xQ9ic zky$xSEA143Mo@3M(Zf;67n33J$m`W03_>x4LFH~)gQDJYDjyP@4#NgxZmm=f zQln_87)~X{)RKbEI=`_2vp#Xj?SbC!Y!^XGmz~el3Ie-a<%?XpJ`Y7?e9d2Sf_4EoBMHX<=37 z1s&&mu<^b_ta3|Sa*fwhO~+dyJ(0+Av(GHSK@AXs3=Dj)M!k_ju2`RHP)BfkEj4=? zKgVlrWC`AbJ`c#L%$A6P;^mg4Gnb@pqePmA!v6_HML*HR{I zX4uue5JT=jQNbkQ;{LASQR`Igr)HiC*|<#zrzu&u9VXAG)3fZ z`zD>V9)(J7_(2*hM*HDWzR3!A`=a>9u3j5$)fL`ZI`VVU0N!R{)vQiBP)BR|l%Y(3 zdXU~e)<{yrsU79Wqs@?|IJtty5Uh@;1iVQa!l7qb&lU2U;cp6Scelm^4=%UZZ`Pv}*PgO~kF+PVxUzKR3^XSx~0gbCK4 z-KtpQI2Ch}B*kWN&934#ZoydZOIAaUh)ItYYQ5FGBR{>0}7x!{~Lq+W;Kdjsa7S{87+jg7iUC^VsbXTfc+28Jk%WTVlka+px#tabit}k>sT{uBZ7D zospP;Ra4uIYA}{Y$*O;@zt@#XkHE!hIlQ3j?=RHEkl#zZd0|R7Q?02SMJJ4Avhl8G zRA}ETVtY`v)~?Xfd*r)!^Nm7hcyT*?){k3e3om&(i*boh;pw131UyfPyNxabxp|aaQDYcFR5{jvbgK&vRm+A zxQA0iu8UyM=UJNfb$AGtU*%78LIrvvW&DSwxdc%S%DyMQSrMvc{(AEqdvlVR$$VxW z9NB2fN+qb(+p)}=EYsbyJcRQE={=cLI*^JU6gx_pKWpbLu2S8abH3OFv=u8aWfc~! zjHFYyU!I4)b}`5$UlK-o!e8^-oRB!YNo~<#nBU`k&+VXYGx-x@u2q4sQD`)O?Xa%^ zinwgH=PLfvZ!4*x+8Y})v+diflRe{4&y>qzr;%4d>A~`u2D-`#C;mF|UWl4SIL_J4 z$j;Kph@2>5u&r~!WeNCzRf7PzIOaw41(nY1NL`%XlX;L3l^8EV+|?Mlzpcp0lSyq^ z$6=8DkCWv}`?U8UKHcwo1wL#SsLxTDp68**((YU#8~xLZgN6Pc%;^j(>im8zPBX!? z31!**KpJSilFb0|Z7cEZGV#5^i1OMusfL_Rn^ha1o4K;)>m9Ch7PmoB=f*_2k@-(4 z5!(@+onmUr^DawXob$H+Hj}smmhYx`O7K1MZx@#C7N(mHocIX{oet)?sdW7>1)`cB z8n@+a+&k%Xm$kxpJsw}~FWv9gG_Er=-Dy-yfj9c%aEbVPj|s(9#?n;=s^_n#R@6Dg zAbjOy@Hp)t+qgbO{P_Mk^s<@&cTOlvLp`F&n7LqZv4*kb_PBcdi9>nu6s+d3?=d}^ z(U5t-+qm8}y@%Z;tD9|u*IHVRsbqUU=aC%)stiep2F6?qA!Hs*78~4%aK7*Gt?a24 zG6_(Eeo0-7yv#6sn&BQChV4^b=XP>@thzbuQ}%QHOVMM-=F9eM3BkJZ-#a2frMwO% z^8l%aLqjcxQ+OS`M>6VZCg^^;1&~c}f^UsGc$@$~!j}v;Uvns(_dH`mwhJm_4mWBgx^A8Ed;pt2g7B-$L}udhCD z?d)u#&(iZe3M$E`{`krD6D0}MU&1IiBP;hc-!`qH+ardyDk*$Nr)PqJ5EkxHclRgH zg5foukny^*DbJ3dbt%p^Agd4wHQ1VuJ=Z~8oha~7Q(LV2;rOg8`qd-wpWozTnmk;& zG%{2YreF&yMF;n)d6lCouNn6nR+shJD!A-GCB{gseav87*bGxR@y5lS6WeomK46CW zoli)RSRa`f{4`t%DtoS*69;0iuq@###WPpvfU?SeVBgvB(N1wKALnpJ-j4 zq7cMJVr;-ru<>I^?~cB!>$G>vVt};?DHNy#&geeKn?y`QyHUekoa#;sYEYgNr+g3k zneLn{LU!3Ff(TbyIIi~eP9-_*$J6{Gmvl=XB&iqa>DMxRhd7f0vnKIzJp#@J>xK%-6cH+RUS&6-1@8#N1$r!4oKoy1#0P3>V&ge&2`g8Ltc+Nu=?lFI znEi|}Ok}#fyCl6P8_VrU<}~3?viFM>o>D_8#*gPV7K=>WI&@!5IP@%GFbrL9 zjqpjBOp6N^UKk$Vqr1^94yEc>e%^;R4n^kK_^R-1FQqQ{cqc^DQWgaCOZAQk#0`bi zW`@_6EW5hY16cUpr_l(_3XzOAVKt^_sK{*8KUt2UM3pYv9=G}2g|+^Q!os>By8W4;j=K0%-d(!U7H4vphO-A7 zR`2qvy&-J-v)kK&W18c~b3KbV9S)X0Z%-b(q%NzP9iWr>s*gkz}p588|7Ap(7iPb|DH%QOj3|_f@=Tg79JIK&BK968SZWCx{SJ|mDl|WqadohyJ#a5?qm^-DJe96 zT`wUAJHyfSkq5c~tXnX_HPRnDB4uksZ1ENKcBa@JgFz2UC&o&MxlL~*epz2yP0`0zTTuf7Yt< z@lp;Uk&gfR8u?~RO|$oE+hLQXUHPj)kui%u1JcLMy(~=&$I}S0yjdDC`RJ~icR`)~ zbX96kW}n;2Rq5*Wm6|lqf^GuR``BAE^Omjv>%8DSWnNyoY5INQy{sD5aR%7-FRS%- z34{0-4|_I|nPj+e8H5ojCw*GpZ#iuK^Re?Qq$GZ!-8uq3=^5u-?ueWahwXhtoV3DB z0gq~_y`U$5EzzimJ9$O3NdcVi7;c(EW7HWT>#Tn*bicID~+dR?tv@qUO!4x|tl8B%p zP2i}a6LNsgl#jciBAY*^me!-zly@NU>)6j*p3A{xAd>=b28%}L>Bidm`GzXkV0(kZ zsi{pyZP!Md^iy{E=L6qM#p^)SLxoLenC02z`@afY#nfJ`*c{*wa(QhKD1N`NM>pC| zuEm(SE}%y#u^GLce)!|oQ&r9!SA`5ptq`uuUb{D8$+D+&@R<69^^{EOX4LM!vPfbH zX@jjdJ#<@T_WAx$T*S}y$9FGBoIqXf=5_@VIblxGMSA1i#QF7gL|9l-u{Out0V=gf zMBE~4p@)*SVpGraRI#fu@8h-JW!vv5NDb9vD6S!jbf{mFg16m)w{31NWnQ)ENrYc% z#A;grv5l3NH~4hBZLR0^sXs^)k4fa8B!22aA)=JI0gwCi)KsXdJV;ib`kuac!Kd?q zX0FDD7<2xMg_i!yv~A10>TG5TL2G{gv&VKA<#3|TziE_b0Y<~g$*DB!`|3O2r$iFu z+BI?6W97}4{0pYJL)!q-Wn^qQxt?zEwy+>y;LgVuM2SqRaZKNnKldv&uBgO}B8Bze zt52iuJV&E`{5NMA=H9JzhQXr}0q{%M4Bi#wtyy6nUPjER_GM4MMM$2mIbrBFLKm*} z?7ar{;i4nuoLBGCQ0kBICYZSv%!Hz0b2gP1rC!a?6{&Y@>~;I{@%i~3n6Bo3O!t}e z4M33-lRo^K6E}mW_>&mh4?O$IuTBkETdlN%guhs@EPc$$u<=^sL$m`FpO*Q0YmyQK zk^x!i;;v`)YGLE~#C)#5XF&q(jOD6^Ra6E=S@3+Z-uR^p>F!8Ma~zQ4b}zP|oM`Rqz@wl&e@Q(rsLFUVQ6 zxDoZ-DbK6XoR+v?K3Ly}3B}!P37ZxOlg8Z~>wI%$nB{P9N+c<_`)M3$B0o>yurWpx4W$_ITbZ^;a z0HYA#^+g#H)fHn0Jy@fmjHd|;5t<@JOt&jha4JNJA9?+Z``^--;C45DW-AN+P2b1! zYTU{?M-pnUR-7b3?hS`fc{03o(|1)jjlNpmKndON!BwW|U+$HBnOr4Nn31tRIGBcw zrP~Cmq4Gb=B2Q@ei=bj&S~u;+&smh?q}89ZWxKBBrtRTkubnSBsQG+UY*ged#IimS z8m;UdLQ(LetfZu%(;mFEUS9koV+TWt=8or(wT_n_mz~6{8L4bOv{BlwXstZ7P{Mbk zlQ~Ir=`wR#^|NuTD0Y3C?klmbw>-^fzg9Z4GWf1?b93oH4dn(Zx)Reb$Y|6$hWgI?{2k)@aB;vLpKhZhCPsb|uSU?klClJ0KEZ@9;$d`Fr{@)iAoCJY$;;KPe#cG7;>pV3FCY8?9oJ&$aw$rtRl! z6dkMZu9TXk<`nAdW8!RzBH=e>QBdP(D5_Xy!~_GHusoIh7F!=q1hr4fHsF^I@=12x z(jCKn3%W746P%)GVyp=3NoG>R(04oPy2In-6=cr6>wPEXd+8G#- zIsrY$5I|2LEC}^KunogXDbs!jcX@s8Q5#;<`qc3hz0C0j@i?eOBm(EO;rM$*Tuwr; zzHls@_z`mS5ywTK)VNf?)uB=#xbDYYjs?2CI9u@dHkwxf&GgUB+v7Q|N5cn~)81?~ z?S!@**&s>bt|YJ#2X9JNRyyz)vlmRPb;L-xn$jtJJ-@klJ{Y!FR@QWN+0t+<=(C56 z^j@O<;pP{0%hBP|^}~GgVXIbR?8!+X&127ObR{uk_HIam3(jM+%SM?6G(eTQ`$dbak^s@3RAwG%J0xzoLq(@MW)!nINTF=8Q`1&Fo z)l`e#`?R@5bn^2)AD@l6;q=QWq=)s=w3Rz)Ud4l8@n))VRi$}3do8HZq5YC)M=afO zI$61F{^X)oOua3jMt5TCLGa^xKfl>4q-wXW`LkgkrH55E(Bp1IW8_+NPXhG5WqJF& zyJw^DdVW{RXTA!VM3?>45#iV&nU}6|50PcHZP+g!5~Flvn9A9w)* zm>(LB#9W!Ql4dkwbnNbMvH?N!_L$6m3ux6E8DC`ok8on)^B5h)(DC zvFM)rMgE`}ts(Fr3IxvZKkOfsb@}AY+_%`s3=J23BjC}R{PKl3jxe=HUeJxt?Rd?W zi%mYTDJ?vpJQFI-+E?K_rW?$_L#bKUgEd#TZZ2K}-mBS|`Kqyk*A}1T_wAs^FY++7 zh}H!Oh>3dTLe9x}!((8t$0n=(yiPo^tY&Hi4y@F)dP1oWPPfPL@$tuUytm&YZHs48npZ~r8Tl01+?s%S zZE!%>f_|g!nlw0Qp^~Pi9b8cEF^_NRr5- z`}@`Jos(lv#?sue_0i_gb!tTIx^7WFA%+?+xADQp|S2Rw(DokCKbS z84My=N9@Z}^$K^Egjl*%a|K&A-2`)(`7$)V{7PK`O-UWhG(m%Tx5mB5TkT3$+37Y< zeKYxE{v4luG{JJrWDdaBM=p$+AML-E@rrRgd+AcT9B85HD9o!NI&Q{hx%H< z$?@Tz1i3o1#bIN;=GRh$Y%0AV<83Ru-wp^8d}w*t*K2mL@DjXvIAXl#R%>E>v{9V& zry1(CZ^6mIaSZ>8C)9GM&{>*yW(-NuZKmBqUfe0+tJxR)?+K;maU3nPNt=#VY3U5V z_XkprW@q6+A>cKwQ!~jQ2xrG4KF5am$O?Q$4Wl;UTwjc11pI{KlUqDlW)f&v@@&o^ z#D$NYcFSDU!qezDHN=vt%7XAeD>Wg=)7MWDB(@|ylsZ!kNugo*OF4u0rcivxL6IBJ zBBy^Bj2g2G0-ouBRATeD>W&yquo;WYw|}DJFT@iF0fFFU_up#mPnlktyWsUwFnEs$ zU_fYSczG7{Id>hH3gr*)ra%2$`x6Ku?{7xF?$YA^=Rj(c&QBeF%W|GPl?Z-Efd*>= zAK4=zp>Zs+%q;=?na~3`3kRW=7%;$%I6gkUzq@%ijb;bRkN$pjP{pnTNU7fS$TZ;4 z|6euemmgqej!&NWiB7*%pPdEYL{mLGTJ1K9A+$KCMdq!ZA||E@bl4=)(YpDyva;A_ zB>Atp9yQ+ii|{9TAtAJF&2?$5FBY3h|E`;T$52#Wj3B&t@kEDC#|+VN9~B%BWn|Q6 zqCoiwN55RulUZ^a_x8Qs0-Ml*i_zCqy_2$!el^)bx($f<)#q+2doP%%;lC)q`Q$zL zExaeMbcal*Rf;!V@S(|(C>G!wC%sLPar*Iyp08n)$4#>hFn8unY7!_ue6sS3FUstX z?(iOqI-6m0y3~+xxh=OvMG@Vtf#HLiCrwsjkk|m8X4&6N6r|j zwm!ZVzonZHOAu_G=Bm_-wc`?2S8h=B{f9sIK2v_SHsNv=jO8%ju97$iLsKnn{ zYxPWV5lc|VZf@3e!j~VfSXxzHQm=>&t-w+6elVf*9xOHH9YMW^lgOZ2Z_;gJFF(l)7sS^=`vr9LeJt z4m^_7BaF7!33(RAbXHa3>b7I3@?HC7=n1u53w2HLcMX^Q43XS!WLo+}1&tQ}+~&DK z4Wzq{Re(=cFLr}b_T)A;X#2$hC&7ACax*Pu8LzQk!mFS&ZHPZN19QIrpKZ=3-g+s2 z-O~%4<_Vgeexq#M1<2^uab0EuoCTfmWetRr4BGnr97i>#ClS7Gcq|9^RCyw7o_mze zI01Y6 z^Xw1OE6gx}zC`46$|JT}A21M0w?@D)f z%P@3_lr+L1-QA#cOAI0<-8FP~hcJ|cqI7o+2ug>5gdnMR<9puoKkxmY5BJ066U;Ds z|7x%GtYcCH;Vi8ZOP9UdO4*mQf z<{vkD*PpnquBt?jyJ~=KioV|_x^2%CV4FVvKmndXUXje(Ypz_@^+O#H(36xPV&TXi z@wGj!7Kehz&bWC9A(ur6+#2AbbXeg*(8(zWbUTa!5<)_0{Q|OzUa`Pmx7XL#>+7JK zKwHUh)LxW_@E(jRs=rLh1JfYA0;W|UYyh$t8ME~G5#{Rn=qC?=NIb{^y@K%X>ueGy zusfACW-i%eiBZcUub-0=B0iza;c75Svp#(IrcRo(9=r;aR&TvfknXI1kVGf0G4|k( znM2;iZbD{V2OMilYwOcaGbDigF33XSK;1<}MV%zGL+gw5zW%WnffHK6GlPC@G;YMx=WkkQ3qW}7%i`}>CjHP(Ex%*S`g(gyIR0GiOs=k2DlVwXH{z1 z?p|Rr)O9p$m%rpqbZK)*ILn+<2Uv&jh@eeQF+42WMf$S{?yF*MmJb#d>~L-V3;EHDgLr~tnIN*3DZA8>w}z7AN-ydL z^?vSXJ;hkynA}uLB1EVEp=DLBN2UHws*fa+Hc#&2GA}KnsNGUv?Jk>CzlZKX;z;9{ z;oPoV31*5~*67Yp1I@@K5p8Y}(T*xi?d@)}B2G_Tk!Mq00gM#z5*$2v4{(ZcjYsS% z9R#IU3}CLn@D9-O;^Jbf>laS5lW48p?0xIlc*bxe*k;1}CKARE8C!dtM*>9|m#D^o zGUnRnHxpC%+kF4%Gf-w+i{BkC3r#@%!Ei=#;P%$ zaUE@m7E(kZSQrtkKIG;l5c^tSl+1aaKt?bOCO;#lztbIFi&v>V@e%>Z4TQy9bU^Y+E+?he5bh;^ zxb(!-WU*fG6Um%>B?X}JP@SN7840yp=jx$T5twOG!#WabWOfw!N{u^6TL3kxccG6J zm=e+v)wIru8EGM%J{bL$Q~~a;=;A2>tICSI^PRc>$N)RHCnWAUe9Z{2D-&h=UQxKp zMflCBxK&Od+cmj{hq9NN)hvaoW2&soKdbfKl`d7WaAbX2_jftM zYlakJ`L~NjxDoLUE=C1utoE5lO*YMPgpOISg6p?YTl=A`$);CTWswVsgFKTk?k`g2 z4%tPohXwNVXQ5-KPDavJfqPfU4NNa6;8OOkWAtX!CCwbT%ct^IIE>HUzQW}l3vMLa z$xP7O|8o!(%xTZ8)n9^454<9{tP@{j_+}+VjQS;Vb~aVmx?W93sCKLQ&Z9BI&-NhV zYShp}wiFM}7o)Y{ZjDwY8nhW38N-u-`1$Fwja_onDcYNNcO zQX`Op9tGZWRgwu!D{Xy2xlX08>qJ?c17mmx7u<0hD>Wj#?dh&84};{=D9O4;oFP06nTmPN zlC`Y{N6BhuW~jjEfW4$cHFzitq}OVkSCtpUSNJ_H>FBK0_wmhK4ye#K^?xAx^!gwuf4jEw5L z(9iY*?UN8Fe#(HNBQh(tW-EtqSiW-T6p`!2TKwYYA_%>^h2qaCvUVFo+Lj`dQk#Y&H?ltQgHr}O*nqe=YLU430<$n;dAxI*AcOSMVS|zKR$@EFR7|>R9JGf1sGWJ#cCRW|ZdS^{Nvi43*h;a)Crk9X`b{s)>pr2mtX`FCu2 z4??8HKN6>be6O?fb41Qyt$g)yyD0~g)3vNF?cZLaw=mKpXT4D`rTY)ibFYhVk`p>J z_hUm0;`9BEqP6>7`5Nu5lGrO^(ZAv2z24$Uj8mU(C&hAL9)0)3be;heQydHVZ|HP? z6%HC6Vy|Zq-^iH^w2TkUKvzm=GEImDX_8) z&5|oemVf6-?D)D)CrjC1?U;{8*tw^*>bY7bPDjkql&+C#R<4jShNifO*%(=Io$vd- z#FEvAI_vgwEh6>cZ!eWZ%VB799z8YMu-lN@!8G){&fiHyJqr_(eLhoP>ml)zRH`b8 znW_7`u#?L-@5ZYv$2^$yt16G*^&K^4@1E=BLt0RPQQ4bXEvqjqY4(wD<)(PkSC@{Q zg(PgtIO0oNEkxDLq~`XwZ2T_8iP36xdT+0wl|aaG5*>AL8H#*TZ&2&Zpf8IV)dIR% zAP}ehDPNCwv2!;;Z~5-J@Z5fuA!(y;sH#PAs4012i>u)Hy{Txcb*ZW0!D@G|X3xjZ zC8&VxV&9IkxiVW;YyRg`L5@TKA*4esd-S4NOXM9$5G{TR)jUJIu#I>0brpGHNnAhs zR=A5v^ie9sJobp*TlM?W*zsVesa@kUFHG`cFc`PbQ+lM}l;U4o=_;gQVf5ca18qDh zu^{~ERM+0jmv5rB2Wva9EIl7D!P?RGRY$;k8D%gNc^v{|i-9P81*`Iy@!=m8=2niF zm5MMz{^BaXoJY~Qog>aPmwIXmnU&84)rHPJ)2V-<%I_Bf$yXV&EQ?bN#*#1-)mr2Bv@@WK$Wi<>c@BzbxydT zZq@$No>y%-`^y@RG(B9V&%nEx7{ZvM(8OH+fqx+_d#a+QSNuAfZ2GjahTN8+9Rn%v>H=G9NLk6c>DDCAzWQs8-nu|6^8Ey4Xh z6a1abJS#zO4RHRX>Iw->58>P{*3cYUCM|RuZe0_!GGNg1334smxmE<^yP{Inc#`21 zVAgoDNRipvY4YBcgJd#I?!MUR(?*=#ho&2chHQ!b5^u4Y3URbsrGaM@Y#I{Qlnkn3 zK&s#9^&m&A(>|GAwy*{*Q`#IRmpFz$Z2dO%!lr7Gr+Qr6`|3{E;YCCt?hL`#W2AwD zQlA=cW58#J31@tsS7QIPX&maW48@RxN&-W@WQWszRthR96+Hl_(@T&et~^1H4H<+5 zRlE3_%o8g4CsIfe_Mo;(-fz%pM-6? za3cs2b3_xmRx_FkJ*B50U!^d^8?Z>!!JpM^0f}KKaj52t+aer<$);{|Gdzvk*l*uS zlZ*vARUO-?gD;ehWdlDCSb1w(QCP<0gO*>b2-W6?Di7vDf9$pnj-#04+SccSOZwPv zO`gZ|NHjjf(0s+-5J_t=P2`za7iAmKgW~7auSOZC7lvI|$$ndt4B?9di>T`G-am*t zZ1ADADMV|ySL8t_`>l$iJ2B#Xmycf;;16L~{z#oKw~}wLdv{wDzLp^vFDO;m=re}E zN~K_3)(S?X{pGG{Ur@=g<#ps^HN57gWcmg&L}=#C>l#}MKJe(*cPa1tqacI17eC$% zj`xJ(fKX&nXiE8=f+ucOR9)>4`Q%B$-n~m7rK^ss%cbUgdpNJlZ`J1NP+l&Zs zrAo0v9a9y?{T4F`X0#~H#WGDRPUq}r-$vy;swSMy01E>ZhxGi~rJy7{ffx;Cv9HY1 z<%tjVvE~~)z0nFBGcfZi{^4NRAG$S`_hFiKyhHZHBl$!^){DZ0bkC$L1p)j-7}BqA zDY%~;DfHjeS%O{_1^=Zs!~jxn|K?!+C0hJ9QGCySJXl9ct0zUwe7ObM0H=4x1vx{? zts>G~Bwo&#Ch*teoe)l<`f(h7RXl!>`{vDqcI4Uzzd zIA7^5eM+AEnCB-p6>iMnS&)MH>*J^c--(VxDMSr%@~l^%!KI% zs}v3pFqZ(_hF%scM))*DZIq%1rT3b;SQo*rNwihBg{l2fUT6w}Ge)gr3DOZ&Jx4=W zH<-VuhlRjOB2E=`pS-@LfQmo;=$RXY>#`p0*``~LUS&WLXm`OWR9%SzMrJV!dNP#D zHKXfN|A<$NW2Lj=0UHlo(7lMg>PhTSz`x0WB1v1ET612lPe(A2E>UZM#Ex&R&FR~g zv#O?!Q!8=Fhk|vn{j*B7I`-*~k&j(ldzt6?+pguKB&UZo5_3VYOgTS|#~9dWW2RHw z@w$-~d&6z1H8&uC@tBC@B2+>i%hC|%f#2o6?K1+C;=#;jg-?clR~jps)=qMZ9${m@ z>GpbG*DEMTmOS|D9ED)uj>swG&gXZdJY`*goj>)tJf>NVl9h+1v|*Rz_lUByRlY*m zQ1$-%h<~+xRBN@fNdhPk^q>K-7{^z|B^~~s?@S&{3m&54lhRXIO_b_bDNCm2jGuSN zC2`Vy>IU38NWU6z>y>0-C9holRW%Cl=fO#eFl6mG&eDJJMvEuq^;I%*_q2zFxEYzt zlQ}}TEM{t5@OR8#qjS%wX>fW4%+$tuoFK53&;XgQf{@x2HR||giW+Hg+jX*-Wc2o7 zq~s)s@Ou1p8w^>Rp;U3+{(D;Aa>XhGYs$8~LnhW+iU1U`q}(8%qxkagvFa~ql9)V9 zQs=O9KvQ~;s7|wphdRbwyWf|U-~D>t)qguKQ+{d~ z9$5}9YZBI{SxGi!$^vxk!RlivgOnrZbFc*I!={3Hah^@+>5oJ;bftG}_Iw6OnY4J+ zRMZ&Jl&^NF3ufgBiPN-r_AjkFt4Y_2*u4U3iU%x*VYle4xo1W5 ze%YG_*`Kg`Jy^`ta%THDB~0fGL=DGq3U9;0P^CYmIrXeezZwbjC3){>)9m3_+jtE4 zBj2Nrp!eXu@&>#M+q&u+>W4VdPT8xAU|WEe}}SWlF#4Fnrb`FoI9LfgD-&sJWvTC4v>bjXY{9Ezs6QNZuOc zr0|l8DMt3Q#6-V~eZa;7SM^r5pGeMGf>H#G|EGUz?5&-)8C-FK6fc5_v=x*Gj~?o@QwJ~O4ioM_movkzT@w37O;M6d zI$(sS_b`wD1RI~Cp(2L4e1zBHI-is20qvqSJL@T=rQ?|9UG%|XQu>#`ViqV{*Ffv_ zlR0B+Nk39EE_Y+vQXv2h0(%qbq@M?A6W07tTz;1w=4(Bvdk0z$A|_Q(ssCjB6_^i4Ke047p zy;-jI=3#hAhs-BVXbHPwD5iotg!zw%X*oF_U`IM-cc@OJ*$vg{SanFM;AmgIbYP)Y zws2RO0Lg8d7 zo~j}hi5eG3%@-J0!qt0dhGe%@RTs}v0D~$cmEa{Xm)yhhiodif{LqT{G?KJ zT$(=uAtw;wo|A`<%%=vHIch2=hqU0g2XoBadD=}gm zS^82Fq{PYGedIFJNDf*yyu_=bKu9-Yb~K^nA$ek>xEr+Q&A&H(U`hi~7kP&K508$9 zrw~s=U@Nf&-JYMfA>Ye z;tmMU@&|)1@~iZZtC~Vs3sHb{^`ATrKoW#D4(gfo`8M3`>@fls;-8s@dsI*aUju2{ zLYg8jGg9*5#*e*DJ=PODjnoBFMWqmzx2Qg3(lMFG&h!5D;=`s=8q(I zTt7gz6EyNTK3lh!5#*bU;;G4$qG}f-xvR7q5pbq`NFypF!#HeGB&?$3jzNF$aKacKk zXgSi+`)K233>V*)u9W8_L$I_)VNYoM>fnTHa}JZd#qdr(Y(@qcnzF$q3=OxsvtkE$eI?vRcmM|tj2*C(E?DdNcu z&_@%~n7TksZP)*V|A|vToNH`rkQKrYWIKoFPO7qR^A3J(oFHw$hpMti^ueFqFKB(6 z9#?mOI%w5fw$4lEl53;Wie7SRQeMpThIhi;B6cAiD$yKSZclaBL|nYAa!c{&&8$@z zAy5U+xdl5t6}EkUhjIQ&{VLllmPt-Mg=>^W)lLhl?HY zzvbkW5&`Rb@s{D$lcNL+nuCd(e2H$ibJ=e*6;hyqm}K3$omo*H6`#uCN`n>;J^9Br zU~8v~{T|1c(8%2<+G&joC23zs1VhGDUxyk#)|2n4U{Yx01Y!l}iD?dW2YY<`DvKWAN@hWGXNdC(?2{0K_0QHdnIcIg_G1AC)iO=S&w`)nHkz*;cH#n@`5GPU$}7$HN#^`^uQa5 zXClQ(&i^;Un2SwTU5Ls=GvTYL=;InoTG@OL^rEkkXAu9FW+w{1KZ1xrH8ma_nBBIMsnPcIG{dBl~CYbdM zW*so*@zi^_ggZmghPoT*Pe${#TNGue8Qh>&$X+8t7Bt-k3Hofi0xQt#0@}2M(u1_zy6lnSMYxHN)q$k+m zf+dL+J`?RWpZ$o4XXpZRoy9vNiLrT~c{nniYaot{UXdb;;Z`#u{*jb&2c0^2CP07f zGmKSBfoC6$3_V}`^aYXF@2ZfPvaH+-arWucB?(b7GK9lBLf)KMQv4L#+@MW&Qa{9l_tYHY4MTx>rfa{|JenbT_P)eGxg|)G+|%nub7n{n9gcY0geaMdRwlaG;pO36}OsmTz#T z^5f+=+@`7@UNFri#g{d9c6h0;(jzpVkbk_-NMLWqOgxtsw4NSaU zzn^IzJcJ05U5D*a$L6z*sYh-{@*NO;SC1`dRpefwPhM7FXU=>5*3E7R-^_|)J!(5q zoC#t!1zPoiKy}&RbhnO~I#s`U(pgO@5ORA~zeSo!c?R2XVnNHPUP53BwX_@;70VUS zGNTZzHQG_TF8fJWYJ;(7t`yujuFNu+IS{ul$%RrxKo$L^^AVPh2|Ty5QiFW&5o!zb{z*rs%*et1xf*F;omrqpe;Y%0Q!Jf9I1=3PC!+JxHbMT z8{&IGgFFi5IqbJT)W}r(aIPPj;EElsVE#+}l#b!t$-jr@)L?iXJr<_j?f!T82=b z!`4CBHYsGLwSlwk0$WkQUg#wcrj34FsEEnAHH&juBjFUOL}xyi*pVCH-EABXTf0OR zB$n<>yv#8iCX6s-I>=l~n9e(f3=xRp5sygo#L%y>uq!MHmf~-eQ3wFss-3RNfFHh&s3XIo(+z&yq&w|0jkavJjWh? z(kQlnt!BrP!yH_a^Lt)+^iX^@uOMouzsg*gC{&JoPvH+}k|`9_S>Kv<)WVc-0>!>= z?NmafPzGy4J?9_+VLBJ3?D|$6LoH9wK{R&cg=x@_%7A2pq+pf&pj<}@sU3NqZIF-n z9~23e-Gg;5FQ5)A=o%>ruj!9W<&W@<9m6xdVx)#i0^_a{7b2t~{19#|)Aa(-k^Xx+!vK+{zbQOe>Q&^T5gGl!>nfyqMS9r!r zxywZ4=fQHmk-UnBX@*nW&BI?F**2qXwDt%ogAM4JlQ&-{Qv;Bxu*sW1a%xEMV37;{ zkT>@sm%+m?o1yhBu`cg%S6mTXcpLSe>77MZSu)Pu!}8+a%h511>-tUR67|fQd5ki{ zSRb_2#nwur@EB>&qt@ zWZ=NY`=dioM06Ksbye)uUT+yPctr14q-`VDtrnYOJ*SJ{=4u#v-$b+J1oeoq5KM)% zoUbn`QE#R$GwYC@44WA6x6A71iNBs!qR+2YR)=jR z%O zJ2IL2fy{LeYX=giHgL2{$C;%a0@uaj@f6oLDEMTac{g$Sc5)wzKTjGnU6MRUA`X}y z;yKVb`~b06ReJt9s>)TR&m`p5Lhg_;B4$%S5fbt&ygvwpc$*UcYM%)cOF7$ggDBIm zCgyp-JXEzBdasxkPn|i z)2!f(%-M5d&Fxp(i#t`A>Q3e3cVXYtnroGYvJ>S;pc6jEOFo34>lx-k{nSEL*0k8Hp)o1U-rq&xALv#Jj#t?>wC~0>^>>2?6_*VlqH8>p_O-b|ZrK%(j4A#h{O9`s{S8(a@y!bl46I9EUGe%xE)s!6b$O z?;>XdoG|gzUKYb5HKY6jn% z>^w>3FZtrZDHeI~I#PJc2yQNZVPT(ST67Fkt)B1VX~`uqXGcY~O_GQM4Q~DXqA(C& z$>X3G*o|}qiSWK! zyXC}fDLyaPc*{zenZ#|0wxp*VyDhfV5ljRLRnkpV?8uG(%7}sLUDVZf&Qw6z^PFzp z@0K3woTMk7dpYluBWqQazyRoYQ`c`at+E6@1M)1l$`3pI1dN(*vnJQwhhKti?Yee! zp@ax$;t7|J;l^vJwkH(2`E}ibgvA3d;D?=TnRO)5a{>|eaYZWBSrt_|eRh%TN}(j4 zg7QLE)=wlEyMihyV2Z@_lTZ6q%Z4{7yexalHiqaX#E;jsX@F*}*;w??1L3(MM+IFN zf&-2*1fIBJXXZgE1dl6PJKRPB2|eM+M8?yYAK$VwRXWJ+R=hp3Qe1dSK@}RbvK_Rb z>98{vl*L*Ec70EzPJ$w`&5A>3$KRFaJvBb5YmYgbC^X_%>IxwRWf?wn;w`6@fB9_Z z=WP`sr~_}ESxrY$Nz)rf`{*Q^;N`Rh!TPocD7$#lPH;D^<}a*4pLX%(dieNg=lh4B zSo<8yXPTb5N_=w>AX?WZREOPp3tYe~pPUqk{=VHfN zT%heJHDqz6575B&^h^gJ79{)5~O~K2_$>Oxei+;&gUE%+P4-x z>Q(y6Zv2t|?{u&NJUS)^RUtJ)EAEbcI{ zF5QJ&!<${y2ORfu<9}0FzC9ns5d|b)vHpJ5F6q7P#7LB7#3SA~k?J@YJzrUQDIKR| zu-Y36yQI1b<{Kw&y^jA;@IKI;eX<>g=txtp2}Au`0DG@J`6JoA=el;0a|hRc^(}O{ znZQ_X!-SA!D0Z*UgMt>G&igHhG)eM^XY!^5D zj{m)H*)nwv$ZdmCpbv3hDVGNZe9u24jCaTBwNmziiS4A9%t+dB7&cZAE_gcs>brOQ zD;hd$8&-;82itqi#XWS{R_}dYDeKc$Fn3@8!-fcgvYDiB5@v-_fogD#uiUvA^}iU* zFR{hq?s#JkD*J|?&Z_J*%JrQ}nW~btRkWlk&R5DM5j*GBif3{AlJeRE-7?Wvr&BQ; zhK`T`s!=m!P|sI$?5;{A2Da$$y1D3;J%*ojLzVm!v#5zePWDTV;c+3ad6$oJxq`t& zZOUL;cGKYkvC?ddC`-1vdWwmUzzVxc&3G+8HfeCH=T_l7Y+d^Im8hYge6*ho)2>#t zfiN<&Svb{}gZZ;KW9_0}*t7bp^N&n=b*;W7Hs9sUL6^vHqtwPcXd(8z+wigvA|pGp zfgb|S($wsgFJcDhxwzpz9yRt_do?u2&bM9-hki6Ya!TFC?WY=!ij_FlMm^>M!>3@T+?}P>%G^|r zNh(QCp!GT-@xaY`jMt+k{Vp^7o3&nS_3>3zV$UkCipCt!(BFLKR*w%jj&YUxK|lb< zyI|e%=ewE3%^kn#3*|wP?3hW2h-_DFFI>bfjZH`asHwcUq|Pp5OxyE&pSy{*_cQ=p zJquqP6}B~!bTjWh-~A>mwUBL`h5T}2RkOHgN z=)i51B(wMF>L>_q15LUr9PRx?-#g|35i*ykd2PTPibk;KKz8@!Ln&UsefnxH!L!oA zbG)Cc6Vf_8AMOs>H)&p!UGKXT4!pXI`+2upb`$X9`uw}YIMG!yy1<8D#MBf;cI>TO z@33oaI5Zf1zOldqzj5|-do zzVKl|%vT0Wxjr(lRc&zeCAS=v{eVh1J@9-T2(Ef{EFgWXM?53tR7;&;sYr@|Eqe5!th~Jb7Y# zM7}*2-lUDo^wMCY7H{vhNBCrQA3bq`<@W)G4?kMudEVbmDZ2)4PA}722XgF0Hu~-U zaH$)FQWzmSR7*>2)@BcWIIMhYb~DL6kSFGTfMB{;b~~GNH1|U}5amRO?rJR;rlt~c zm;{!1q8ZeFZK;cqx;dYn8k_9sy8pzSlc=E@26*yjKG_R1a9 z@-)YSng`~k3#6Ym^{LKf)@k;CgggAqTlJ{fgG~MMd%wb4xr*P}{M-yB z-s^dOciY^#52V9dJ;!1Kh-T5A7ICN_c9Wqn>Bg1uGfe#COn#J6sek{ONZ6iA-7L=NK9(Pb0P_Ds_w!>1R87;d9+{%9f>P_37bm+(V^ka|bL zK2}f{W^(n>{Lr-WcCzP8fg0O&i8$sE&W{vwhbA zj5m4(^z2jMtTDR)Sw(&)9Z(g)`rV-8R-UyGxpZadyW%020KM=8hHF;<${%eAONE7i zLwZ$TJJLF$;6uMt5%PIzs{|Rs6#4%}h4Ocj3Nut~#@osKcYBY1*RPSAz*}A^SBaT7 zErgh+L3Q_j>t6I?#C3S7RqIRMn{LH9;U|!`Fc5hDXxZ*PF0!-bgIbg(B*0$p&khzFR7P&&a zJ*FR~?KevZU0q(%p3b?SGq=7~*WOHd-R*4U=EQ98C1=XI)r6DoqlSqj-a-34Js#3* zts*i)o4{uc)}0)m-RP~JD{FVl7xov$X^D7I1US&m!amHw9@0lHke{Hdfo|e$=`W8f zaIN&S!m41t$`rEdFiAa@N`zA|&#GCDzyt6h3oN z0%`&*UwJxDp@TZ)+KbYD)Tg1INO!hG0#b5U-~H+ZNzajnop@T`i@|#>F3o~VZ3D0n zOD#uW0u#3HyA-6QN8rvy6(wpw*>xusH>8`^IWg)L> z^kO^+G{#fz?-^S*S@C!Nm&k%i-+sR!-wwj`lb#9RQiuA=(7ifD}$K3YpG*|3S02Q$?i0i z(RGxAUp+LVd;x#qcd^$MzY}RmGmCY0)pMTzcKp#0dJ{p3kY6{Rh|j>?u$>^45x6bx z)~`7;MPTQCcW1(KB^YRu3Dx-Rx18ic)-FRolLK|-8$*ikEQtHkrX1WS1TsqU_a>cJ zRpn?#d8S!RUlgQy?l>zv09F=RXRjZ=pV`XA^4y7yxfvNmGmm#Bd|=SrF-cgY!9Rt5 zX7w|t?rPVR+fYQh6Lxe&a3abGzxsgU!;)2#{Vu8w$ytfo{eG=|XrR+TPpBtx1A~7) z$SHY|Qzvk3s;q}k__nFzMy69O^1v!IZs{9epz+eyfObnV%*F&WB+OAVJlE%E(e@3^ zw+s#K7eYkN)UjTY4~z!r{p*-H0i*NBUdcnC`9J{pEu8V-LEW2qB%}M3{C&egX{(-g zOH8phoCRKQ{)hta%`qXO-h~pNsIl$n{tDjy3ezy^rDN}dH2e@UyiwQQhGleE{;6qdKR!bL zY$@N4jX4(sB7}>M(??iq@yNhYPsz%7a1ya@nVA!3<#KD=M=TWhYoSbQ+8-FEMZE^@ z6gGNDvyIJPCUh$pf&NnFgSc+m<>Q(fGh}kkOu-bGyf+sc<&Od{ zFqhv!9pesXqn+T)#`Z79f7mhFE4MOmn)48YIx_#)jHo32{JvbyEChbLsNG3ex$Efw z>c_MtBN*hLCJe<(3U6j*Hlka&<36iv;+ACTNcvwF$Sgm;`I}^@AlV-2*ab>%EMfkx zPZGlo2suRLmrgxi*RU{kG3%<1^GvHKy+*p919>!~(I<=g`I_110^Cd_GvsGh!vFWd zz)`U}lNH;HLiW(}16=pYKh7a}#-JLybajXpKs7YZSy4Om&zF{*y%`MuWKl?2M23s* zI2KHTkpA|MSAavW|Bv%QhnZ&*KWI;xA{~!Rr0DtQ>{O23XzmcZ`<({@vKjC=*{3yz)LF!~Ig8vU*iZx3B diff --git a/builder/etc/builder.ucls b/builder/etc/builder.ucls deleted file mode 100644 index 073c5cea7..000000000 --- a/builder/etc/builder.ucls +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/builder/etc/builder.urm.puml b/builder/etc/builder.urm.puml deleted file mode 100644 index df8d73f36..000000000 --- a/builder/etc/builder.urm.puml +++ /dev/null @@ -1,100 +0,0 @@ -@startuml -package com.iluwatar.builder { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - enum Armor { - + CHAIN_MAIL {static} - + CLOTHES {static} - + LEATHER {static} - + PLATE_MAIL {static} - - title : String - + toString() : String - + valueOf(name : String) : Armor {static} - + values() : Armor[] {static} - } - enum HairColor { - + BLACK {static} - + BLOND {static} - + BROWN {static} - + RED {static} - + WHITE {static} - + toString() : String - + valueOf(name : String) : HairColor {static} - + values() : HairColor[] {static} - } - enum HairType { - + BALD {static} - + CURLY {static} - + LONG_CURLY {static} - + LONG_STRAIGHT {static} - + SHORT {static} - - title : String - + toString() : String - + valueOf(name : String) : HairType {static} - + values() : HairType[] {static} - } - class Hero { - - armor : Armor - - hairColor : HairColor - - hairType : HairType - - name : String - - profession : Profession - - weapon : Weapon - - Hero(builder : Builder) - + getArmor() : Armor - + getHairColor() : HairColor - + getHairType() : HairType - + getName() : String - + getProfession() : Profession - + getWeapon() : Weapon - + toString() : String - } - class Builder { - - armor : Armor - - hairColor : HairColor - - hairType : HairType - - name : String - - profession : Profession - - weapon : Weapon - + Builder(profession : Profession, name : String) - + build() : Hero - + withArmor(armor : Armor) : Builder - + withHairColor(hairColor : HairColor) : Builder - + withHairType(hairType : HairType) : Builder - + withWeapon(weapon : Weapon) : Builder - } - enum Profession { - + MAGE {static} - + PRIEST {static} - + THIEF {static} - + WARRIOR {static} - + toString() : String - + valueOf(name : String) : Profession {static} - + values() : Profession[] {static} - } - enum Weapon { - + AXE {static} - + BOW {static} - + DAGGER {static} - + SWORD {static} - + WARHAMMER {static} - + toString() : String - + valueOf(name : String) : Weapon {static} - + values() : Weapon[] {static} - } -} -Builder ..+ Hero -Hero --> "-profession" Profession -Hero --> "-armor" Armor -Builder --> "-hairColor" HairColor -Builder --> "-weapon" Weapon -Builder --> "-hairType" HairType -Hero --> "-hairColor" HairColor -Builder --> "-profession" Profession -Hero --> "-hairType" HairType -Hero --> "-weapon" Weapon -Builder --> "-armor" Armor -@enduml \ No newline at end of file diff --git a/builder/etc/builder_1.png b/builder/etc/builder_1.png deleted file mode 100644 index ec892c15f6c48e8e6585c308c19334018167033d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106529 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
      X-iNQ-lhx*DtDx9r# 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 diff --git a/pom.xml b/pom.xml index 79bb7e533..df01809f4 100644 --- a/pom.xml +++ b/pom.xml @@ -463,6 +463,7 @@ singleton factory-method abstract-factory + builder From 3eab4d75a69eb6d44a1e1a75b57aa9db9021a837 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Mon, 14 Aug 2017 00:16:29 +0530 Subject: [PATCH 331/492] Revert "#348 - Data Tranfer Object : Added module to project." This reverts commit db10b937f2b07e8357ebb0b4eb02ca0972d83b25. --- data-bus/pom.xml | 4 ---- data-transfer-object/pom.xml | 16 ---------------- 2 files changed, 20 deletions(-) delete mode 100644 data-transfer-object/pom.xml diff --git a/data-bus/pom.xml b/data-bus/pom.xml index 22b3f0229..a77b59106 100644 --- a/data-bus/pom.xml +++ b/data-bus/pom.xml @@ -27,10 +27,6 @@ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 - pom - - ../data-transfer-object - 1.16.14 diff --git a/data-transfer-object/pom.xml b/data-transfer-object/pom.xml deleted file mode 100644 index c5bfc7fa8..000000000 --- a/data-transfer-object/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - data-bus - com.iluwatar - 1.17.0-SNAPSHOT - ../data-bus/pom.xml - - 4.0.0 - - data-transfer-object - - - \ No newline at end of file From 9c088b5f478360e4a7038662b49eac62af341445 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Mon, 14 Aug 2017 00:23:03 +0530 Subject: [PATCH 332/492] #348 - Data Tranfer Object : Mofidy maven dependancies. --- data-transfer-object/pom.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 data-transfer-object/pom.xml diff --git a/data-transfer-object/pom.xml b/data-transfer-object/pom.xml new file mode 100644 index 000000000..51151349c --- /dev/null +++ b/data-transfer-object/pom.xml @@ -0,0 +1,16 @@ + + + + data-transfer-object + com.iluwatar + 1.17.0-SNAPSHOT + ../data-transfer-object/pom.xml + + 4.0.0 + + data-transfer-object + + + \ No newline at end of file From 8525bfd323614ffcd15061802c7c60c3a2cbd702 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Mon, 14 Aug 2017 00:40:01 +0530 Subject: [PATCH 333/492] #348 - Data Tranfer Object : Add dto module to main pom.xml --- data-transfer-object/pom.xml | 57 +++++++++++++++++++++++++++--------- pom.xml | 1 + 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/data-transfer-object/pom.xml b/data-transfer-object/pom.xml index 51151349c..2f4871cb6 100644 --- a/data-transfer-object/pom.xml +++ b/data-transfer-object/pom.xml @@ -1,16 +1,45 @@ - - - - data-transfer-object - com.iluwatar - 1.17.0-SNAPSHOT - ../data-transfer-object/pom.xml - + + + 4.0.0 - + + com.iluwatar + java-design-patterns + 1.17.0-SNAPSHOT + data-transfer-object - - - \ No newline at end of file + + + junit + junit + test + + + log4j + log4j + + + diff --git a/pom.xml b/pom.xml index 4f4b5dee6..cecb0f75c 100644 --- a/pom.xml +++ b/pom.xml @@ -143,6 +143,7 @@ extension-objects marker cqrs + data-transfer-object From b62d431d62e22b54131a479221c7321097af7b40 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Mon, 14 Aug 2017 00:40:29 +0530 Subject: [PATCH 334/492] #348 - Data Tranfer Object : Use logger instead of print statements. --- .../datatransfer/CustomerClientApp.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java index 3a9e8b88f..f5fcebe03 100644 --- a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java +++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerClientApp.java @@ -24,6 +24,9 @@ package com.iluwatar.datatransfer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; import java.util.List; @@ -38,6 +41,9 @@ import java.util.List; * And The CustomerDto ({@link CustomerDto} is data transfer object to share customer information. */ public class CustomerClientApp { + + private static final Logger LOGGER = LoggerFactory.getLogger(CustomerClientApp.class); + /** * Method as act client and request to server for details. * @@ -52,20 +58,20 @@ public class CustomerClientApp { CustomerResource customerResource = new CustomerResource(customers); - System.out.println("All customers:-"); + LOGGER.info("All customers:-"); List allCustomers = customerResource.getAllCustomers(); printCustomerDetails(allCustomers); - System.out.println("----------------------------------------------------------"); + LOGGER.info("----------------------------------------------------------"); - System.out.println("Deleting customer with id {1}"); + LOGGER.info("Deleting customer with id {1}"); customerResource.delete(customerOne.getId()); allCustomers = customerResource.getAllCustomers(); printCustomerDetails(allCustomers); - System.out.println("----------------------------------------------------------"); + LOGGER.info("----------------------------------------------------------"); - System.out.println("Adding customer three}"); + LOGGER.info("Adding customer three}"); CustomerDto customerThree = new CustomerDto("3", "Lynda", "Blair"); customerResource.save(customerThree); allCustomers = customerResource.getAllCustomers(); @@ -73,6 +79,6 @@ public class CustomerClientApp { } private static void printCustomerDetails(List allCustomers) { - allCustomers.forEach(customer -> System.out.println(customer.getFirstName())); + allCustomers.forEach(customer -> LOGGER.info(customer.getFirstName())); } } From 4a81453da403fd76744d05e72b36ca84155ffea0 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Mon, 14 Aug 2017 00:46:31 +0530 Subject: [PATCH 335/492] #348 - Data Tranfer Object : Make private varialbes final in immutalbe model. --- .../main/java/com/iluwatar/datatransfer/CustomerDto.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java index ce9ffdb78..7dedf891c 100644 --- a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java +++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerDto.java @@ -31,9 +31,9 @@ package com.iluwatar.datatransfer; * Dto will not have any business logic in it. */ public class CustomerDto { - private String id; - private String firstName; - private String lastName; + private final String id; + private final String firstName; + private final String lastName; /** * @param id customer id From f9789d6926ffaadadd1169dea65abd2fd69d06f7 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Mon, 14 Aug 2017 16:14:23 +0530 Subject: [PATCH 336/492] #348 - Data Tranfer Object : Add class diagram. --- .../etc/data-transfer-object.ucls | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 data-transfer-object/etc/data-transfer-object.ucls diff --git a/data-transfer-object/etc/data-transfer-object.ucls b/data-transfer-object/etc/data-transfer-object.ucls new file mode 100644 index 000000000..15f777aad --- /dev/null +++ b/data-transfer-object/etc/data-transfer-object.ucls @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From b639f3630e6b842e6f9dde50d21069abd5d61131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 16 Aug 2017 21:09:28 +0300 Subject: [PATCH 337/492] #590 Add explanation for Prototype --- pom.xml | 1 + prototype/README.md | 49 ++++++++- prototype/etc/prototype.png | Bin 37751 -> 0 bytes prototype/etc/prototype.ucls | 182 ------------------------------- prototype/etc/prototype.urm.puml | 82 -------------- prototype/etc/prototype_1.png | Bin 97668 -> 0 bytes 6 files changed, 47 insertions(+), 267 deletions(-) delete mode 100644 prototype/etc/prototype.png delete mode 100644 prototype/etc/prototype.ucls delete mode 100644 prototype/etc/prototype.urm.puml delete mode 100644 prototype/etc/prototype_1.png diff --git a/pom.xml b/pom.xml index df01809f4..4976c14d5 100644 --- a/pom.xml +++ b/pom.xml @@ -464,6 +464,7 @@ factory-method abstract-factory builder + prototype diff --git a/prototype/README.md b/prototype/README.md index fe9e17917..e6d5d8b8b 100644 --- a/prototype/README.md +++ b/prototype/README.md @@ -15,14 +15,57 @@ tags: Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype. -![alt text](./etc/prototype_1.png "Prototype") +## Explanation +Real world example + +> Remember Dolly? The sheep that was cloned! Lets not get into the details but the key point here is that it is all about cloning. + +In plain words + +> Create object based on an existing object through cloning. + +Wikipedia says + +> The prototype pattern is a creational design pattern in software development. It is used when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. + +In short, it allows you to create a copy of an existing object and modify it to your needs, instead of going through the trouble of creating an object from scratch and setting it up. + +**Programmatic Example** + +In Java, it can be easily done by implementing `Cloneable` and overriding `clone` from `Object` + +``` +class Sheep implements Cloneable { + privage String name; + public Sheep(String name) { this.name = name; } + public void setName(String name) { this.name = name; } + public String getName() { return name; } + @Override + public Sheep clone() throws CloneNotSupportedException { + return new Sheep(name); + } +} +``` + +Then it can be cloned like below + +``` +Sheep original = new Sheep("Jolly"); +System.out.println(original.getName()); // Jolly + +// Clone and modify what is required +Sheep cloned = original.clone(); +cloned.setName("Dolly"); +System.out.println(cloned.getName()); // Dolly +``` ## Applicability Use the Prototype pattern when a system should be independent of how its products are created, composed and represented; and -* when the classes to instantiate are specified at run-time, for example, by dynamic loading; or -* to avoid building a class hierarchy of factories that parallels the class hierarchy of products; or +* when the classes to instantiate are specified at run-time, for example, by dynamic loading +* to avoid building a class hierarchy of factories that parallels the class hierarchy of products * when instances of a class can have one of only a few different combinations of state. It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually, each time with the appropriate state +* when object creation is expensive compared to cloning ## Real world examples diff --git a/prototype/etc/prototype.png b/prototype/etc/prototype.png deleted file mode 100644 index 073b472e5cc3b7899160c3780a9a050fba0d6544..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37751 zcmcG$WmJ`G*EYNW1wlf(yHmPLLSoS%NOwsif^>I>i%toV?(R7yiunDI=?>I3zpsmQjlcp|ran1&(3! z^h*~Vce9}+h+bMX;Mx`+3~{`-lG*I`+qPI>?tVcvvrEX-9me>65yAOL%alBPTEiUL zXYh%!6X%a2DzOkM$>{65uX1-hc|TP?eE2Y#ul!~?(gSZ&MNKVL@T`Eh<={#a9|~9= z@F!e6aV+=Ozo3kt!jQlJwTCT#0s>*Ma9tE|WI#EPe}@4XiA8+Frs0jE1c5T1(UnSk zeqOpTRF8THg~Nb8aC8MN4p$5V0)+@mehq#FY1Ny>HG-E!)Pe&>@s3hK_hs;ID`)FP zi^8cz27zdxN%N^-)uDZjO`|ADSZoPFAcZF)O0tOMPhbazNx;Ge-+3RWnIzp_ic!?W z$@P>A+H4L z5?lRGWW!x~o^y@8DW5GN-Wl+L2!cF2j@ZAbbb#}qx5>KLEg>fe5j&1m^G;c~5H%*0T8j8;O zMjX;=*t7ex;uXZJv-Ja@9#nYIu~KAeL%ytDl+w=yO>K&*Tr&9GdZI32rEIEE)B;i& zFNbI>O=oZo_FoFmsKBd3M}{}FqyWN2gP8`DEWSRiK{hP0?pVU*TOIDb;wJDB(X%>1 z+hCnq|3kMbS0X8K!BeMW;>@b-QrJksik87YugVa{bU$;yJ%Uv2MVwZlRM!M9e)c7O zekKxmq%9uSog%Qtw4TVWwC-eJDV2{%6k0|Jk^%ivd9;!wo_o4gLFIerIljXUmwu;%)2}vCGd5o3O^$F{6@Z%(FN+_j;pPbc>V0=*(I{H(i$!s#KPADGb3Qt;<(S z73thHrxEDWwoP>y12HPYeQC(OF%y3@CrMAyWWUk9qiS=z`dl~b{r&eIAxqDri-ggZ z_b9{T%P9Qz6%B+~3#HcDszOXV%7*6OkcrjZs3uZi@bCS$uVO-n zMQtV1acPX`WPfAdg`A8)4JKnhTqfRS6nZb@e%%ncOukgYQto%4)Ef+S)3C^NGa(4? z$vnNs%&Oz$-j|NE#5n7b50=oKkj=F92nILM+TEt_Imqwdp0|>Jzhmk}Q(*jsZ9$bH zV@@fxCi^HQTFy&h7!SvRFPk@(E^g_~~H_@JV2 zac0wrI2L*bN2&Q=6&bwND~nuLiNa~@AJ!wrx~0hph$raCt#lJk^f&)5boq1jKZzEEuoCH!Kc#8f3O^N8276SG{+bbknF^Z@Vhwt%WA>Zrfbd zG_9-U? z;+KP5VzM4koI5p5!QbTa4H2#sIr|7b$HHj!+0mGeanYC%zoR|vM0^nasNQY^hrY&F zbXTIgg3)8|)+{{wmyeGjNO@iyxiSfHc&>dX7vi}!<=u0-KW`w`*1cXkG5LNeA1G9( ze;B=^I$!f}Wp{D;!@L&SR|fjdHYI|_wRsOd!eN!UBowR=csWdhWJ?NGnfJr{s71|G zCt}hQSc^{0$<4^Zsk3$0!=JZ2&W~=~cNq%n>OV?kK|a&jCiE1I7HuKz)byv>KjG|e zC(?Gg*l1a7xmq)g^nBxZvQ#zv&1Q^AQC?O3(Frtp4s@W zif&W^?j5Bp)QMrS!$Oa4kf;Dd9ZTsp&^l30k&Uj#S>8$bxoYB!%gL`7P3nN57Y$_j zmq}rWj;$^8-$CScoHvLcBv-V$>7@wBDTS(P0KF6##fX=*$#5{7ivz;hgOtE1&`!YqHf$XiWTrPxA! z&El_{q(} zx*y}*L*?kJRm5!@JyaC+s5@#igoV3_#E{!j6(8ts07qb7VDmoi7gx5#+t`=a$Vv5h z(eCp%QRCns%Q41%jiomRNX{3uZWop1+Z9yNlq=5A>d;@I{|Y!RlGm$X%@+4f@*y~l zmaA=)v1Jsb{q>(kgeT!gQ66|dX3)2=yq|rFka6`@8Z^hpX=4s)7d9&Da7{FVQD09(?qtp?}K^m^nLUc zoc|KLPe3+pB08!)v}g)PEtK#`5)SoRZF_9gdoKVc}Vw-<2$q2d2R%dD@Y`PAUf5yl!b0N)@XPhIJ#SpU)QGr#O4fcGFmQvct? zyJ#!PcT7_zvYTtx*{*XkjMsGLc~JijaX?I_H45(5M>h&yuWmOSF#cojBoxLwn1`W= z^{xvECWd+hgos#;8>j&b)$C|7uU*fp>->V6J_gnG)G?*TGB#W9uTSHk#+zJtzT0EL zs)tS2yM})b<0=5Rb$j38CNy3Ha{H0z%jBue`__@sne!(a=PQULVtKaKpCBGYN}KnB z;0^OGuR+HoJOj-^F>e`i3uCuHnNe^Zh@jz#CVT{C>#Wo$KQ#qE{EGDx!KxSvb&6=p zB^8C34kMxQCh7IOj;9yo)NS4tcBagpuM3@&MN>c7$v6J58 zwIUp!*LvA}b7~cPm4;8GxNF@NVKOnC&Y6HC_{Lj)qow@~$#9~7N4Ai%3(stx_3DL4 zG39y~`%x5SAEF2^7pXSGA7XM_-Wj0>t(ZhOZ%hu}_3FE}IKVKt$W*q{jD?TRB=Z1DGV+UpG@l68jHtea5H(etRkSmUZE9 z82PL-LCQYnhy0Z;s^sAeiM-MzF1z;%;<^%uzbv zwD5XA*)9m>i!mPfZG%7TAN84(Aqq*vvtu&D1_4)FM*nTFwz<)_54Ky8CF*PLbu68Z zFFhafNHxC9BO#JtLBHJoR_KrT^4wi|UIgPu3xwbB1N>jx6-8Dc$qxMwlZzG|yTl3- z9Ip~kwGf=FA_3>t*1Z_pmsh6#*JEv>V+oK0a&sgl|T{v;LUul-2FT-fZ zyC0oTeT_|c1a&ih{6+o$@3^d$+?Wq+=*);c?Yc-+N594-r8c;3@paDO%e zyzf7AHnH2N%BwvT=2zv%7m=f{_w8Qy6_S)c8N*PO{A1=+pC}j9PEa`djr^l1qjF1q z@czl&SUxe#YO>yxOTG`l6;8-S@?-y^T;S{w~Nh-hH{=<6{zUD5(Q9c*F zFI^GQGDf@I&xVsRDbU`s?65B48x)coqqa=aND8Sj@5iSet?xfjLlA1asm}`>N?+w; ztTVRVs(ekPvsP7er7|_h?nfA9FE|p3(D-CRMc+@2SNNZdYm{_bJ2}sD^YUitxQ^2* z%x4XOLUEwGH3(bm>nBP_vmdX`yT^3uk47d`Nz_?iC*|UeV;>{7PZJ7Q?(@I9OhX>W zjLfBLktMg;5?Gj6S$rxNn1DiCqBJ%f$gGZ5*e0GmYnv( zV`t-Kit`G))kw?2MSB*O1Y|^_TV&eyoljG}61~pKSGheLvSX0$MltS(#D}q}2xQpj z!*=^ng|JB_e$^4Ds}$-paW&@jU@Ay%6y?ISfPm#5!QpX2*NCr!=2PEo)B0Wu#+23v zwojDi0s+lzfhzy8aedP5)aCoZvz<_Y(5=qkUdKB|z;i6%DS*|uCn33Vr8WLAm)x|+ zpcTEESKSM?m4VK%^xsdCEE;(YJ$VhewrSV}jHS@b@oFo4#KNWu#?TR#-kcODq<0b) zeC%R($O)MS`)<&|Y$2XYxIr7uy}hizY#0PLysDtYyj;e=gJ}S#EW=iD*(|^q>qdj& ziEH6XdY4Ha*l?1{cDRT72m*<)~)Oz=6`>t$oD7syp_BTxd}txl238F&$jA_ zJ$<={=!YkGNg{)1#`{Y2%g-pn*5~lLz1)b;Y3h`p)`ucC9PyUXR03?7nK+11*7wpT ziUzgk=NnW$ij8(zn`f~&p7I$VefJ$+neD83_@H-cW>#F#zkOVF5}K=K9Gp*2#Fe)R z(G>ry{cmqawNRXrEiS{qFnlr{uC+YPV;i19yTFaRPbpn^7F6)@6Y{^7S|3>4vJu?H z_ifQ?R{J#mJ}1>%fjrw_UJY(nT&}J6WjB--LsvK&>Kck8n&;_SFB*%3FGKJeOj(Y( zq=nR%xv(NN(Qx#XwhVsA>W4Lx#MMt=-EGHg&dsyZit!J6t{8r|7t)>?=+|J+xC2Bv zO+T)wcAhuAKSF!)**Wp=w!=m>Rz2Krzu7t2|D?Gc9LvN1C%1g|T*^kk^#Rk=n)ht? zNckIq=l8_5N;~luS-u`WyjcH$BTX<9xAyv#BAKBknCiLKF$a>dl!!T9XE{_bcP0Un z7MMG^u}IIQD_I3%J2w+exj%Vj$>MY@y5dWilPwe_-%=Pn77u^>rja^mnY=FRwv8Y@ z+<#}r>&A_xmK-f=# z{20VH$Lx9)x`Mjg)=f;+zvBXvnN5_N$sk1|D_S97dn;B%=@FP%UPYmFlslpv@w7jAl+3 zzD+hFBP-Eua6g9Wnm6MV=de!z^R8RMkfbA>2R>N%!Qxymd1oNdD82#@L?D0%2G18qy4ifE(XUUC#3 zY!I8q4gOc3(0%nPPzo}lyHju#h-VB??tfK~sA4D!^PeD5Q9e%w-p%3qhtHGY ztG6>I2sD-93T@j=Xi4qY!`-h8=)**y%c3{V$#Uz)P61RIzVP%9Ywbjq+9T2$>^@sd zvQ|>r&L^Wf$HWe;oY1G*)^Qc@}9I$#juf!q#xoWHN2InV__acz@pZq$`RI&Whyt? zO$wMIBMLZRN(eWXh-C`Esk9rg{wfK>;Ql96|Ia`~$aC?%@htrLYW3pVwo=L`(<|?O zI2POchn(eC;Q5Xe>aR^HJ-7RsfuL1Kru*!h=C*T{1p`vO!Ew7%Z+g$e=fQ$`38anL zHw&e-x$HUNmWDlV%Z>C&&imQAI!KQ2_B_z*Z>6T6e-lJ1W%xt50Tep8JvS}Z)pfJK zLG2kHX{j7{N*FQhSC5_x-x~~ChTmPlLZp(^Qbgq*!vL}Nk=hhSIThL`Tln2;>ooLV z?!bCXTxQgj>MP5bOXHuGtTQ+0qUX&H-s=9qE8caGxVOdag%>(uf|EzP#cFseqM0&T z+qR6iZ0=6G%Vej6A@j*bCT?1It4@8>+{+j!AO2mW7W-cU4F*cALk3=5ldhXxqw>Yz zbNGEpCW6XjRySTTIBV*{52 zSkKbtLpC-WaXaDs(|0w`p;A8Tadq8f?N(+Hd@z#lydrO+-(hbp2TGfN7tqNVDBKrC zr7T4V? z?#T6A)6{@Lg2L55mh9)BU6a=I5W>cl>T-UWZyF(VIA}Llo3)&q+OBUP`L4&-4UVqZ zx$Pm}eE877S=0~bi~pCWeKTn0O;v|B>mPE2=+=(*uL5MpC6%2yT6Fae5ADSlc+NH5 zEW(@>ts$IO*n3R=S_r8(Gyr+`f=Ro3ii$TRiL+dZMQZT1Iz4`sRa%A zwOtNv3C!o$!5?qx_LZiP>{~WAOLsLF%xA4I12O|s9T#emx3BKZZ5jVd=NgdpcMD%u zPq9RBbLv|Sc-nK#bMhUim`Hmax02CR0?Dz}QhzKg;U?rrbINpCEUsRFo3wmNKS|M>`OsblA68e{^j| z7{mMgWiIDatewr=sHG&D4-1VMwdA&2R4=30<+BF=N-c z`>ED)l6o-6$LPVy#YMaMR#S6;kJQ7uZUZvixXD40$jQlhECN?LH zW>Rsr@cvuV3X)BR=ZRc&x@y6PwQw#agcG@-^t-#e>6ZI5O-;>{lao097)R$kNjXKJ z7-7aMR9C^V$R^}m`QXJ2uFbA5T?*pTkKYZ^pv2_#VSrM8EV6pt&Mq$I1bJFpTfcuF zd+&bO21naC%%|vqjErnzVuFlH7DI3B-JN?#9_@&(uCA%;{oeAu z?6>QCkCx?a2eY*V@uj|_ii!&5lIcZHE>2F#&8m5;A`F#EhB}LrQ-BUGYYI;1KH_*8 zX{{{?9X5?Wfdng^cZ#?Lr;$_2pXGNj5f&sMAW*QC_wk!NYOu7iQRYuo`$}fUjt7W` zyud0jCe_KFV({Cyn{G&9QBkxi>59bh%Mz6%vEG>fnG2C-R)jBF>lKUFj&NL*M?bbMTX^YSjlu_4varTrQDheE56PI##}0%~sLSjv*xZ`^kGoqb#KbDaEA zkFZ}l!X%>=exEQ59+vYQ@Y>ZBb@dD2%Ic8vatI6jcq|-~t+o=0;gR~@s{nyu4Ns~w zrB5K=ITXtMpOE|0j59evU(A8#rvvYuhpusq0V^9@2X!*p4Y@>wS*;hmc}&nO^bhK& zq<%Z9GG_JT|Cz(wvNV@1R`)d!J>@02a_qi^IP)xXBQ5uab5lFH2sj5j;R)1|cj@-@ zp&d~V7zZOu4QV3&06^mJ(AqORJiM@=HG`;#!TxP{_#MuUjkR@5((zvQrB26FnV=wo zh+)sCetj{T-B1Q zGK>DOo+jKs=bJxf&S1PkW+9~_Ufx3wKHW6vfGU!b-A@OkoG9lC#Asq@G8 zQu6HjNK}Be#+_Wr4Pvsa-~BIZMogn@RvXK5IWVm zs;a7DVPn6SQNr1`r+js))oO&%D|3Aj@39?Et`y$PFDhimVG)-yqCQ{^xDl zVk-TI;*yf_mYxX0@rwM;8ZD_80@%#B>WmZ=l9C~{Y{}ahG9+NMghjpbo=CI6ZHqtF zvcJ#Nb<})>11M;Y^V21S9zJUinu?FzNr0eH3}Ey0)D#|8Wt+*{00!?*OZ`V7pt@h6Zb=(Uh5HG> zX9i;tAJR}#0X{yyR5?=MVDheIKp0y{f9 z0s6p-Jz8E0Sm_(V*I0iRRSku8LAUy#b|MSUfJr}24^8vyx`Dc)pe!q0JOge{wv3~b zlWWt`;Gj&wWJvR3eJ|R>+#w4xGq!Bxt#ms$QWGMkEv>ixwoeCDnDQ}&>_tFOnx39M zkrVHad%1~&92lTqT1FfzLgu%Byt})5d~BZroX?i87Y~gKy}xz0xzbAJEDt9{??qD< z${v*=O>@2_+yANr4Ib#f2m$qbJ#K`ma(=I>s;W^rS}-S!M^YO=`W`i^Y+=d3C_GXD zw&>%qD9UNKD?=`U(YvVuUG9^1^SKO9Q8IJ<2K_cIBil@iePdKk|6N3;@0`il3y(OD zb_=NtZ{IP(T%)^Bg+v|dx)|ymLU)YgcUTWW=tF?{horAUK<|Fdf9=3a=wx>kqd1k| z8wYP5Ru)(`>me0&>eBQC-Pyk{hOgx=ac3GkeZix%j18z3VW6;y+RBHQ3NIj(q_!qy zxw*OmwMcX4?{ip#BMV6Vi`+WrjD11K64ae7AvSqVo6JXRsk3YxwB9+U#_r;vr;kMf z65|N<_0*6;8oNQ%G6Mlk#4??dlZrbk5*bM2s^D7Z6*_ggkoo)}#T}T>zeD7Pn+K}q zg(=vTmxoWZ%6k{I?7yn(KdspAoKgY@u)}bQv9$^?Jc9uJ5k0gK(j(;=%U(z_QhBG& z8bgcDIe)Ob%W#*oNBfPK3aoQ6a#q7%_HnDOfw3Xkz_1@_320`QKRN&qvf!e#T5;i;OLLXMQ4J%(gz(yQ} zGX~>PuI_E|N+UJ683y5(3^Zdto2{!(5>rF%^s1bm^*=15oc;F{w54TbEJ8x*PIM{? zs|mi00lg+SO?%bz0KO@;i1{&)Hmoi9TKeeCMG=#y1`o6#29=z|;5P7)cd4avF9Fm! z7(9m(68)Xd`>N!1Gx)|qaz;iA;g@aQhJe%`D-mAii4HEaBFfDP9jSZMH8=)X%KQ=o zF$i;)AHaIz6~|3vUaXG@!HoH7jN-F>A6hleD&UMWmM!`8=)Eys;hGzSs_cJUw{Lc7 z$(l3SJUo!;31tw^!mLLRQ-I{VSa#}VKUT^p%2yTmGJ_vTM^%(y>D%a`*PlKb0-Dk* zz~5^b^g~I92M0UT_qeo;fzwd>Cd_M0sN-LU4N^0Ui&pG-H#axV)M6asVUHunG6qQY zjAKjr%cY||;$Bfu$+HajN5v=Lj8P1kDD&cFo?_5%>irs4hG+hutqp4NX!{fVV--WS zQ0>VG!sAJ$O!xi0$LG;6xm38A5|Gka4`nUHXgQG!_kRDSNP@afp?OBohEIyybq|tC ztU(+TaG490;K541kZ{46|Iyo`%Xy`n7s_%mtCAoQJZEb=LUU@D8eJpD)IB%jJ z6bD-b#s+~#5X@qtyUYEC&IhnW2dxL?_xp{ktgHZpUXbG^K&Fj7k@F|}5iqrL_H&RK zS@=m3I~o zgz()h7U*uYzyY9y0#fdGA*)%D40fhBNScT&d=vEO*JWoe?uLeE?0U5!3ZNb=Q5nv88;vMA6637RpV z<^11C#zx@`xX+-0t^j3$K!#>D^BDJ=sR-J=ijdlhyKY@X7G)YQs-~oT*35J%A0uaH zo(Axb*9DVbP4cL&C(W3lFn=8xWqDB@MTb6WKbISr%jm1jOi7wa-KX|fJkEeujiICk z3)5e~3bQ<3*L%^=656PoiA`r5%r}1!7fNb^5F9vRT9GqTX{A_2^1I!9Xg6*wO1!y<91&mKX&}PEIZ`v6SX&T15u~p+Q9}!JF>a z;S$>Qok!kyA0H-fOg;nY({_^^#)U@HxLuu+_^BA`Nho&?r@)1eQK^)D^-9}o;QE?Z=T(N!|YEf^>CtH7Y}Sk&%EwpwVzhE7hBHh#jp2R;|N2_-&z)l!bdm zPt!^8y()o&B#=t#;^JamU0sOZz&N@tM1i{tOVqMTqbq5T3zH^;q6ps-JF76`h1LLK zSrQSfR%n+_#+eU1)Uw<`Db)1G6(U|8&bRLq7AJ~ueFa{UjxHNav)3=$*FcziHAlX} zegzr9gEGdVs4{0z*_Jw~BN#GiLWa&YgSuW+_*ODGPoJN2-o*P!=Z&)7dhjfGD-qMm(j3g+-jW znI=rmqj@W6XGo#FAO+LRnS_!mt!w)L_|o=<3Sds}-@m`}5IVpRZ|%9%pJ$4&e}Umg zuIOhIHu^{e!(SU_mGs7Hy*m{4rUL;E_JyW7$?^qyK0{`246xjV$K|rFkAYvhkC)uH zH@vGsq`r6D1qq;9Ule#HJexgl*5k?z3MUv0H$;p+aK%;<<@5V~_<%-mj26_?^t56kv^3)5nl!||Eg*D@*qMGF%`j`= zt+?a8ykT`lt;bI1V-TF*ISZp-TCnt}9WXd+YV-WE$lbG~N&BM|G^wbou7)_#fh36^C-Mhik!G0MUxh#uF&c;x zA3t5NewTVtP$kS6;zM9*y{~3ncn5dF?ZF)I{`+P;macNcsk$pc1iJZ&#I=OQ4@R&X zZMql*^K?IrHl>NFY2M_!E64r){jnRQwFcqLeA{inG;l^J&|e{RrtZbt=zdLNK;8Ok zK&JmqiK24vo`dJ()yl&>*F{_21oY5hDZ?BOG#Tr~C+q@cblCHV@my1IJCAZTpXqkszRmOy9JT9t@s`KG+;=tyl+ z=WO(w4Y!2<0Gh?x(%FZCc1=g4G7WHy$k*N8X!0+M@`$uijt#Q-KvraE;ZR&uR3-qz zh?9Egwpczav%mf(NzNC z3SR=StLdm{=7EBsP#72S`3 zhN(ye)TgX*!hi6vWN+|dDJe?u$Xpc)z5!)JOJjqCd1e^ocUgl|s^`NyjnX7Un`}Y}?`b?!Gt1(T!8-W4IJ8 zl|P1MlTQ3_LQO@5C~>|#8faX3^wF49t7~ecVzbBAT1FI*3kwTNyIzcI>lY=J`yEG# zG!@=-M?t8Jm8P!p7c|_O<59at0DwH5*-R`q5aF$xd^ZY1RA~J@@Cc+p^7U;!2-J_@ z&y8`Uq7|#q+GBE~t)(?c#-5+VK$x}HghJxjjA=KV3ntq^r5O5Xb5<0Y*dla>eINy? z*+qfW7=Kpw0YWBhnf-*|TFTDIT_&+`MTKe${6rRhsYj zVQN}`!MSe^L~GXkBP(?2G?(iNR>aFeUv!ry-E(i+gYlpe#EhFmrwtlOtgF*4daPeV z5r5$>M!8Iqo*_Z+U@o_C@j)?zUVDSh00KN4}_W; zZ=+{tr}17JzCUr;cYf>e-rdWFPM>YkL_0e2!i!3^^8!@(7V zn4QC`)Hp~?ysFbV=w4h5UwB_a(Cr4iNa`+>b+rY&bpZ7i6{(y8s+SdL(8!WR zPtN)>gO5|Sui%eDK)^qJu&iCu(meX{tVs>W&%T#V%dWXtG!93%jeZK+K#iv)N(059C(LJVjW||^mp!}6;`%d@P2b81s9qn zn8%Bg3>Ll&QlN4~koXs-5a`K6+SKvPhNKmLc1Ah|^|8HjL}pmm;d}k*zPJ^d(#ZLt zp;3E>QtI`sg8Pzmi<*+9IlNZ5iObdkowKi@O!Yw%y{oGREz88nfu9wA=iyh*?_2X1TM1rG)Z7>5a}OUSm@k(E?^7$^ zI61mswg~Qh6S(w(2xcTQc%!VZz~r-5p_pys@2eGtw|)O|vOoXb^^T|BY;t@3r%B=wpf3}R)(~~ z*`Gqm8UebM03>h|fAG!^=DaesY{r9dRln;&%%gP)cmceQokvBYt-YM>S<)jBG71`9_?=U5Lp`0z7MI&QZ1BCUnbylwp2F2c-L?3UO}KTf^OeQbtS%EU~P4)ut7v@ zrg#y#@(ruvB;c09dcMB0O`E9DOdZVYNX6v3ys~m(?NQORGsLw#?iop#?&7?57lJf3 zYawF`OWZpN2N1-!9aCtRttx_1WPR?!rprO9B$?BzOw^N%-l6??q9XrNhcdP}i%wzY z1{5*w%zVfGXj>E}e`e2RFg2$@pd&(#ey=B};IL6{Bc`v(-%EesXuTfgMSx6zKx6Pnw|Jq|*NY)Q^)y9mr z0;Sb{SNiJJhM%x5pqq%5LH^8=h-LcX!UJjf_IUcSH1Phg&$rf!=4K#W+c|S-Sr+2v z_Ciq^fm;O;d!ZOnf$h)2kIKbt@gKgw*sfW}J_~2m=QG~wl+k+n(D}V_6;N9`RW{StD<5%)4e5vb2L?U_xI0Tntl-q%sL8Uw~R_bW}t2E(u<5( zVHe*J@3mXgo5f+*@*@gE_u!p!%AFTq=KdHl54JdS&lnvYa8kLowFMX?5EU;jE>>Wk zmj4XMX72e8Q(E{h954Su@>GP^Zz4z^2LRbaZ!$a)B^)=K92(DroJd~ ztuJEQ|9cV7u`pBR0{tWoA$1jZW4dzzC~@8Y^;o8{BKu<})u;LeNH zgzZ?Oi1^1kB*Y23Iu&mwYx#B-T%4ddOutb$Eo+4F7~wWcg=x>}==0(e_xigPP*b^J z+J;U!Gm#eC#`i5M8g86>zjWWXkqlpOywtWhuJW%U)0?)g4urPAC_B|{VF!&YaS$SPT67Og{SV?@ zKq0V6r)4wA0w8ZJ*rF2)a8%9H9_p*zNX;KosWn)6+SJw|kVg0uC=MrnNu6?vwgRt$ z%&6i4o!x};PC?jIpXCDY|r!F^I4%A;z6_I^AQilM2t6(k(*bZ7r%qpI$DI= z;b>Pf@y%UT(YFeA{)?Jq&*NKB`KH_OXf-xoJou{Y^3s^6WRKT#`<_os(bLmK5bzxL zt2H0X+PI7Zr{*l7nO*1Sj&|;PtFDZjLfF2%E0Qtzoj#Gjz{^ZNc0 z8Pq6h2VEAJ#dvSHeM{3ndFlwga7618?*fjv#!2bv>1817jGLRAZ$r!)Yz3K*noQaP z-8J`amiAm&`lIHN>*}Uzdf`%*1Q)%lR-FA6#QXhGyMH8mtROb=?gu!i_ng z+>mPHBt*8X!B&4`NF=Uv;@NGx*cWtPbP^R^B1I@F6dVycYj3KtxmUd4Gt#|{edsQ} zR9l`kbnTV9jW>m(e;ION7RIpRdVZb0IyY*4L33e^jl5ZZB`!D`!@3H+<)>)eqeJ5F z9a>L|F`S+e_|Ds{u$E*1q#(w$(hIa8vRwqK74zGuM&ECs=(-Iw9b8q(-%GI0ee5~9 z&~`ljIv}ro6S1ZShmZ}j{_%p}t7*#L-v370wguZE#8kmJ78}!5?$r#T+#yn5TjI5F zyQ`IPGhb9kESYOc>$8Tsa~26CC+g)^vJ*d%IL4GcYy z7j4!}atjAH#m zJpt2rS|}mj%XBq<+r^E66QjtMkLP`Rc^bY#9}lEMBaWKM6j7JvmzQ0Lrl!7$S2}u= z!t<3EADwMP`jCjk*@ua8a=Dh9kmS7#_q2W9xh z*JE%?H{z_0T@|`l2fMm+4{aC4i*9>rscSubF#_f{)D61lP6G0!2e~uVCd)gv>SQ?6 zF67s+Cp0@6O4uRwUxfVALQQr)^8Dr$fTb_H-=+=74=r^6RoYY{MR-zZ&gOVvBJ7enMmS4L$P?vQm=hh zL>aqeabwM^NY$Vl!C=R$&I1Rwu~v9*zcvArDq71&beZ*_$Mj^h4Q`Ag{z4e~;!x-5 zRQPAt`mNK=KYeSyU; z3?mw7OTl0r#jXex=WdvnPxhN77R;7d8k0~H9Z-L_`=udek{fLQhgkz{vj5%Thko*} z4!<#$X6*Wsh=u10S;-Q9Ebt;SeQ->>>j>9pxymZfl>B08^aD`>UGHsZkG-W1s>s2R z%eD;}NNMrRSby&bFL=Dx?x+6ZxbNA<=kINaDCUe7l1W*vA4{Mctc>#M7X*vx1b*P7 zaTPt*-=Cx}vp$&aSrE4z3AqPrA1z!zWLV9KI_`Yfi7cs)wWExsjDCX> z+aD7pr#0J)R>RG9$FqZ5ObSNxdZf+H{^UI^&ex3TjmP~$_o?TG#P{o5@=FhcqNnlI zo?FqHFK<3uY>&6@=xB(+TditIygwOYiX(2O`Y`Mx;AWpFO{uI-b_3xhPFUB`eesn# zRb&x8YHV1oeF&)=HwKv~t9qqLl9f{P_}Hl{=al128SrSbHDo9((!tt)^Qt+#(P#J?qV&e z@C!{GL*ly5iBlVW^&-4gBQ)RoCM<92&4pitD3XUFYjqXG-2d80Fp3VrjRfi9yN_fI zYw`gEmvc$Lq12wSvWD7ZReFAk=-!4)>+I9gf%{IIyx_O_J>u)@qUk#xcf8tBMK(Jr zA|w6YsKbACI5yA4+F_r)v8~M;YV2c@Af{(}OwXe~C}LQ>Y_2?;Hx(Rn%Q#C;zbCo7 z8~H9*CKPF`zqZ(Aa;oRg+cLhtOPb7}gm?e7geDc(L=r==Yl-apkgZ<-B~cq|+c&Wz z#%o>pjJnAF$uf>O6O47&!e7^Kh=O*AVsIz@sON;#UVU%Fw*Dc!G?WWD(k?DXi8`-6 z`dPB@VTbFW{w&3CIa?r$s_umZB+SjO#q+YE4ws6%=drg!65l& z43h)bf52g(0~MzNJ~X5+pmBbk4yU9*m>GQpXoai>VukU_h z1qc3}+CQ>Ys+V*NOt5KV-y7ab)jI-RPgc*QDymDDlCN>xGJJAtPniEU3~2FassP(3 zu*6<%|G_N(Uwuk8pVg}c8qkj6X{zHM7tky($W9Fy3m^w_0gxL=5H#Km+;#cof*~Pf ze&l%An16qh5zpWqHw4^U|La@tEVD^j{y<;AsTDK6OV(Kfxd%)JFn-Va;t)yzv7EwcVD#@aHb@*58<%_3tBP(Jwxx$Dtf62SAF_5x)8>2H2}2R@#oq>re#FiTp7C6NO!o7CnYuFc&#>pMH7zwhra-_=?X>bnN%m zs#>;$mT2R6PVuLYy9e?u8AdRP@kw-fEZ*Px5upj8sN&X%9{hBtI$GX?$>!P&L-kxD zC7$)utZJ|^Wa`%3H+V%E^HSxWexbL6r@}Vj)KvN<_05Frtxj*1UrIEUPO|NjUxT;8 zQE^JnE@ba!|EBwgf#m0|%6J*I{uXm9L3c^j_j7#ytgb&)uqKV5Bu?|%{E*ZMKk-wR zf26!tc8w&Ad+fh-x_XCRMML);=9g~t=+vQU>2DEolpK|QTdJ8NxIbjCEoKFa&Jl{d zIiHd`_&)9d)B8yzqXq@0<(T}CbfNWh{zZ%q{cF1{FgG-?^H#X;FtK>qg%kO4lCx63 z^Et)mJIecwyrOuku~>`?EUFa^C;infIB>~pFi(Xq!9th$3YFYVPyMWWM6T8!5)CRb zj`E$hOD*~;6yvj?|K2sitOhhKU)}FQ9bnv=T;z}vYxkHI?r2QLXv+RHf$YeTt(@XY zv90>a{g8ho5;n#TPcp$aV4FQXT<>~^Y$E3K|%6Q4Sytw5QAS5BT**yiW`#X$Ljstsz?YD z#|q1b)cjN!0S|8j1OYtPnym_=<;(xQ=*Q~fGYLK5w`Sag+33CEQh}SmfB6DU2s?`( zIgqa+3W5ga{{MU`5uv37gD1=dEvR7k9R{fF0Bw>g9YEt|tnXtq1STjW2t~N`q5@E2 z;|EMsE+(nOwx$+vbgLkSv=T(5Dk`br?2FR+m;?W_|Hq1|C^z)qAOF_p|KZd7&Lppu zVZa5L*9jq2Ko=(!-0zYq4;J8!vX6Tkg(H!rhYo0@er&N9pLh`gv~v1of8zRk=Z{6? zUq!F~T_CX-;{QuSr;`QHuDSB;Z|`eGu>75>UWzN8%oFQ*_x3Lfy~eL=(FB|LKa=>| z=0U1vzfD~RFTz%L=;2I*ieBs=J1!OZouV6jwKcNoJCr}Rb104POLq9HyHjnqc=KN4 zrMe-IrBPawci|(CU z_0Lm~fnOQ%kq&n6F~oZbMmV5&dIq%vS?FF$jLr!BhIr?QA0u9Sl0c|9`B#WmH{Dmo^H)354JT z4}oC82_7^AcXxL-?(PH#0X7ocg1fuBySux)^DT1DdHe0#{f*n>_Wj2gti4v%teRTS zGpqIKb2|au8`@A4yr1H0P@fzwNO}++bWBxbUy)N*pdj5m7_I4qA0&$wK(kiwaHkG+ zH6hxCw^EITNB^_GNrKb=E9iOQn!hjXy_Vci-p`J?5BZT{p{^O#@f30`f45T4T363}Lej9}`WuP0dW4()Olch{ZG*1(wmC1u{X9>$1YuM@Gz!35QdVf#|=WN6iakS^CCDISH ztF;k&{Gd%JMV$eQI<=T{JV_*~`pcMSCvaC&f8vn!J@lE74P5N@wWNX*Ib|NoOdMUG zOxSD+`H`?zsCnKUH0_s339!5W zon$J@T>KXbXq3R3*@Wrb8^55jISEH{>;TbWe4OI7Xk;=*@4Pe@AS9v>K1n_AQ-tPls$B)f})NGd)eR4<$AKn0{Zpr(GCtStKG#hZ)vdNl;TK`u;&;bMhgr zj=3z|^q?Bp-YVH?8QhBMFGn3D1r#K%*DF`~gpGxsPZL4eVWY5*`#c}t(pnX36s;x{ z!*6G?uJ++Hm2$rAmj7*38?Y+;iOA|GO9%cpPcM4iB8<*V&chU3r_sy|nkInL50d0= zF=(>4?R>h{ar9IVjCq@>I`L-|WD@P&{wTilZIGv?)En7@Qm_DR3H(o<`rYa;3g@g6 zK;iV#@8NuQv9C9*wKQT%*2eKwpsP9=?C2!e4U@l7YG}K5stpOwb<^Hh;ycY!zK*Il zD^nxF@^tdRB#}sh`q7HUimtSpl##=|LWF?TVD=uRiS@xTjk?1MT+KIXX_4km{O!`u z(p+SMA_9Rbud8=rLEmc1gd+Fv!#V&;%3MlSpqgsLCQD519VtHp*F_PEwy=1wzmS_ijpSFaQ1#W$S25z3W`+0lZLFbvmcWq?^~JUXY52`bENPqMlh` zu_80yQ~zVrqZ%lve!j=|1|s4U?*rgvTr#+fj6GoJKc$@Ako0t%HdLUX47fvse_3LL zko3O^md_S6ahT-z-hV=x6G&y5f1DqK2vG0^8ez$?@p~2)Z#}!vL}HTu$8+BQdQOI| zEl*fRMzstGVN!#DVZfY1D*x->5fW@=0J9NqxO>Yeqj_<11j=a)KdojCx!yP^IJoVe zS6dR#_K|T3*$-xJOsbqdiNcK-o2Uf4@LU3j@}muJ{R4Oa0#6J4#A?z&*C)pi67nssV_Vkr(I zmRd$%<}$h0D`yT`Ezh;pE5Ak1jcxk{*VYWSJ>$$&s$O1Kyhgd21jwcSyYGHtbi*Z% z{Zde~Sza^9+n7?LEWIKkKw@U>zX;^?wzwhcko`$rVMaoP3Q*=?5vD>cZv3u>8=YDmJI5+SOYlEXkk&mxbgKORqKkJEwwXDH2b@AtZ zrrf%lziWsk={uO$@5qNz*lr(0<^#xgUnoagX1O&hSPxs0TFS=_KDUr~3lR(R<3;+H zokV9=9n+#m(a2}Enltn0cb8}Wfu0TK9mMyhejfx+A?c7ci{E!6*CbFhUcRRc5-)Ea zRyLj7JMr$|)=n90T>L4jGYwvFVNi%b=y{mEzHPC5=(2p6vV2r*US3{Wnrekx6Om(h zx-xZGNZ4FtJIWkX*iLAzxZjIm{&`yLGVQF+*KcWMD(CWt?DTq4)`$5F{9a_6ZFqn+ z7m`SBS7{Rf3Gh|{h*9a%>!<5xo&pM&|CYV#`l>N0i33lQe&(4YWlo5r^f$`6!J(N~ zOtlc4FFze`L}KJ|f2&eYEl)Q(IaPQ4wwgS~BHV(P*ZvZSi2We=uGMq@_6_E!$<|K{ z6yZ^+6(|w+mLT{}L=)D7$OV^Yi66pV>8xJ+P{7gHFLfJ{`b7Y`#A&ku9G3O>_qVUo z(-D0qlMtw~oG^#b1^`$~94y7X^%Uf~3We{;6M1AlJs0v!%QoSbqz`B;mm6OOG)E_2=r)2e` zO&?%vMc?AY!UNC@N-F@w2QyO&u(>0qjG1$U=VxY8Ne)w*1=k zE_XnW=h>26?mt*|mUF(h7IN5xIA~!?(&JhQpzlUBRaaH8(4Nd)YWC?UZQs`jReEK! zG>&~;6{f{lfTOKBN584N!wF!6;BeZ%jS`PCEJClXNPu?Z%|&t2iJOIAAL#C!lH`2_#JtW>_`-z?!+O zPwZ>erryP3!@GmU26otfO0~Xhb6+*o(~X2xA&9KF(SE0|aJYcghw zyygyHfNPK*sOx`vx;x8Wst?kTNrGJ_MGU?6R?HWqJ1nSqubEj~2HQ2t45mu~W0dqSGWvC-lL{`8ZsRKAw=S2hPkji+%&;XxZ_Z z(y5P7S@iS(hseP9``maF{pnHyBG|Y~nwyu6nMvwQB8){cbHCaWjf{5{tEFfDm09uf zBel;gEFj%SO~6O%0I;JY!oraBw8jnD%^}HY;vqi9S*T46I@PCciy{|DWQd*9O3JU9=mQXnjnQ%w9gecSr|{m4BU! z(-SGHsHmu`Z(KigYCUwCX`aV_`_15Rg5U?U38mQk(_k2coUuOd&_8B&qL;~qO zB~Tg&Ie~1_>^*Gi>;jqvjTh^`BFg#x_w>a-EL6)28ZL=dCgD{lxc2Ac$J{55ZY1NiY9UgWY2Tt(kcarl6~M_L2=o;d*kD>>~t zlA_H3IgJ{Z?0VU*3IUi>yycs&hN3sj8{Irl*52xCXZ>`~`^``L0K}a+eb$`&dck(D zxPR+Ynxm`LRUtq=c3HhQWR8RH0SEt$h7xZ9j3xqDvv_-)5Fnqu`c!D(h0dG4gKX*4 zo)3V=8qgr@eEIYHY3mOFW7^00-a0LCAKPOU+s#(ci%NiQGUahLMZ&tq*=@&w8vvJO zeaZQhGrcd5MY=N%qaus?S8VI0EIm8EYu9Gl1HkHYAwrau7|Z~EL;T>!+~0T>HSdd= zAqt7Z$bO|d9RU#WK~5U$G@&1856RaJMtzcusm%E0HQULqJBwn)vkj5!feX@xgKc6j?@)4z%Q_y-ym8MLZ3F1=|0`r&09U45V8t>jul#?tOt7}I3Naw z5}?wCmfvng0Zi~wU1IT4KlRREPQ}wIJDGa@;0n1{D(NrC*8ySSc`8=y;I16=*Jiy4 z``ZwrQhp!PgpCaizqy06ypca5+(!{AAf8FtZ#oop4w|N>Ny%^+~lEm|DlD8-19M@ zsguz^Pxd&Pq`W~$2omEHB^Emas?1b~f;Hd%0aH5mwwwZzLYQFp1pETLHRsnH#H(`#(CNFMB}eyKTWwY3hp{IB*DEXj zm$8*c4PFrm5C24|&SOs%kSV*j7D7k6UPrwg9Ees$9mhagvwIu{03~GE!Ru=f6}Lq z9&sH}V^x&$Ia=#BS~7cmFMQ|dCiQ~e`YfdRCZwr050S&DLP|o0-ldo9m%8Jky&$lX zsx^=Di{HxUE$SuCRnXhD3(1m(>_fW}s;gjYg@!o*y18!AYZY)77*$_{1Xv>elC;B4 zRSjDB=)Mc;8$x3Ymv0vvkeI6=OV{~HC9T2gMCb$pMDKd~96T@X$BXfeLt~TzMsp{G zW#ey8Z`GS}-`41f0n|T66?OA8DJ9Ckf(dDanZEi%2etECpl5N>{NYcQv=qgT9rTRv zczx%Kb%=FQ$m}c$Ro{;*1wAxJ@~p!V&7FdZr?K$zWY`+_@Xngb%9M+nJwS&`3+=|r zb$^wsDR@3LArzS?eD$%V9xVo}8{czG@VXqac%n3pl5{sbY$}Eec#4Xz@|Ex}5=nlX z#2_=z=Us>UJ;QSVmaWzQB{m@QFT|QRqW~Y5znMW`7oq50`xIDG^Pa&z!a8>Z5zHWEU(?8uNRLd(|~;+~-)$+!T* z(k=IkewaysWET}aI4I#EvS&wx)+F$}LR z&|bkgRXei)v@FjZG1bS3$;(MKQ(WvLiqw&&uThJ0VJjRHW!Q%W(FNe{`ydjieyx@J z3~^#0M~lmUIy^esN_v}$9gRE!aQf#C9hPz-=47Vcgqr)@%U->LXnC0@3r5_f%a`Ce zu_?D z)0Y_MHWVL1R&=>LOcY4sW=$(cvR_A`01tBIOvEK6Wi~sLliC8@u-pTHipk4KuXfSX z=T}?H{?(9J7}L}?#|}_s>8(_KpxY%$DZn+^l&D`U;$M#Ldt(f%$0q>!yFehZHA+4s zxUHH(Klzc>K#HaY!4-7|$>N2CGY4C->=LfK(!^wEffYvrZ zZst#rNi=r^b)NEyawMM*5IN?zcyE#1xt$NyHDB-FQ_upBY5|ej-lYpnzGvR}BZRnU zCY6_-Y=k#7F(hWAVN1mbmytBYJ(j|guZ}i-}F~lht%aT#SWD3bjusZ<1um=(m7a;Hg`{V%F zz6yj92h=wPJp*{Ag`!_Qnn-vGc)j`XfZ_Uf|pQB5;>CQ;? zeDfVbg6y65513Kjnyx@b#PT_>AHc$ir2ax}1k+dEW)QQy8U>`mNq&z6-`*izxTalHWMVT3 zOB#(>tOZ)ScFCf8w3zuF0FwpSf-idaTHb6*y9(hga-9vCmqeTM!3@KMyw5J6vDRs5 z?hXzy0N*~GAIRgS=q!-hAa%^m&4K15+eyJ^P=|0NEg>B5fZj7PBkh7{WXBa=x`05s z0KTCf4xj;D{TvL1im%V9eBj^G=0gHpQf6aWF{Ia+Tie^C3TULjj|EDKH3O| zAc--^xv>eLA?%I;Z?+wVRK^!z_}9a}qoF{PuOvyK$Ef5J$U)??uV!-3cS}o4S-%8} zr+rZ{dZY*1vsnN7zV-mz-DA@o%*YBaG*i_%b z;^*hWt>>LKYF)fw=Toe95E!SyI1#0#c&rrB8F#@j5#X%h0}0)?-)ZKVSzOC3CxIev zdh%5Nx*2F_k!r3`_UdkFVWD7p|6yb877pv-1B)EP^xUJFl5*BtCKjYNTEaMAp+G0GuMQ zK=Z@9UNok1(@&0T2ivwI7@q3BQQ@^iU#WEF5ZcVid69%JtsAfDUW_()*5SH8mFt%mt=J)IU~#w6uy9aFBHq_yjq zf3ma7+5Dk{a)L?x%d`}VrFY5oL@qH=s%7?AqEAR}6qY;`(4>6lGxk_Ux#{uWsH7AD z$!(|`#8c|VXK>yp1Tz-g`9xBlmZ9Ik^+j1H#_c%f!eMa_iXu{I#;ADyhe(_P1CJsW zQmP}iO$`m=!(3l(<9O;$f{_~dLsL3P^S#h4A{*zUmP1yQaBmde0c#XlHUHxh5-Vq5 zXb9+*XSxc^?$gWc?2KtpjWD&l=i4GOGR`ko7@E{DvvtHg(6Sy1x@eEDgn^5WFtaK< z2$Wf>(D<{b(472Dd4i+@AjuX!>Q(3ZVYe2aUFCzFa2Gx*R0r)s0U`|Ww>&W8=7#X3 z&@}7)%F~i!Hg%QEq}k0qvqb0+_9oyUz@KovJ~%e}g~Nnv+kBf;d(|xN#fhvnK%213 z^=BF+ay)TSNDt5!zk5J=8-geK3lDkf$*|SE@2hl}{0TW7K1FkD9GbZNI=l6qZ-c#p{1uw-gSmZy6;%Lq_w#&ZT%1JV7Fl;IX8$_md3^&tZ);+~JLv9nI|ap?MQS=RM2jzH2|niE1YntEjpOI|3Lj`IC%Ddhu!6PIj+NDYkUR@fzT> zx>ig|?A%vYR2}V19S;l8e2oOO_7p;hQ)BoG@uSD5MVZG zh*Zvi>r7bPPKWY|ESk^d&XtmyBC1TJj-1od1i9+Wjqev07NP{^&)w}-5ptCUgPonk zvJ_G2Y>zE#`>2j-snuL!koc-C&cCcg$dL^nOst}*DarMGtc<}`SNf%u#f)!!*V5Q| zL9ZZ%f>(t%?$WirO-;bGhx-Jp?9!bfE1{Ezd;h#81Y8>lGHGy|sWXheVlX7TsyJxJ zv$W^3Jmi}G1?@OChjH^#^z|2M)Eu7v^%ak(geJ2ki}WXhES=a+SHok|HKFI;l4Zli zhNCCF+v@QX_=&sfa_67Rrm8_c+YUVhxF3N#AC~og6wzwAGfmF7r@|F1TCgSzCM6|_ z6Pdt-S(r=J5OdkI5lEb5M0bB7dHDKH<-T`g34GGH+VI7V+?oW+c2s@Uo@jV57=tlp zDFm%{+#f@Wdtf>503c2=ldU3ehbF^`I+}v|+_asYXIak_@rY`|O||9Fx^XCD$N*Tj zAj#Rf(XsQ>{qU{&Hs`YI75a9Ju(XYY#^|wVuPt@cQKKm3c);t~1)Te${0K60l7{b+ zk(A)w-<)aWHOB@=$z>#NWwH(CN2pumRJ{{YXwG77*Rc6zWtq8~8jD9h590_61;X$3 zY8xqXIWuq1yu+er#^wE49TL>4T_>g!b?vZ!tbI+Pa&Jk>j#Ah%U5DC*Wg)Zv5uvMc z)+&T;>2Yv9UBx|IbhfZ;@zi^c^5yc3)%gAx+JUTtk8ooPaILYxKq*-XjRU>vMA7YYN&6{Pk+dc{+WO zrlY8_{_HbuMO`U5%q2DrNVw!wgE!*@pAbfklw~%PY=68qP)*2Mf&-Y3fJ=F9ZajCd zTxUDJfm#0r`3&U|F;Z=hcx$bN@ky@ws5DrFp3mB4Uf6mwrtVG5NrV8M$U(j)`fQ~h z-)XcwQ6O_bT@P{E1dl%2Ex&;JW^{;F^jM2TS|&7qLepvgID5U3qmhH*&`|PXQc~Rc zyC(IkgCXG0ZKm?`gMlIFE?zC@%lg=A=r=)8wBkOczi=JO9M zx$zIrzf0AKs`W_|19IG0VoUu*&J`r0R}ARd%HhVrWN`}Ag8AZ>?kAaTE!{+(pH$`2 z=tpc9!SFb?!xp_pLp&F1%N{G6*VsiHQXWs`u1%M&&9{Tgm}qz@v#uxS_ua>hC;r0+ zk9?@hr3;F+S)sF&KIXAoD9B`5Qye`;Cw%JHi;gKL$AR}1i&(I_+5~8cjGiVJc@-4J z_%VL^LgTFhTOCY<9&9RsF_-(H=^C+?`cvv(rN3Y?L2!7S`NvS?6%XLm(2&qAo3F%U#viA-hbJd?XvU+P-j5 zmeAE5C}@~oeH0|YAMy(^8uiy^A3ZM<0T*~%pFnl0nAOJcz%qd(DqVaR0SH-}3S3quv~b zeS2)y~R2Z?~77?w05@ z?&h>K=kKevo`6iw^YN}(>)~{n%Vx8JjblPw{cPW=5?efmTP~O(-mTW9-;n;?=}kN4 z;uUF)xN_P%jn66avE!}4c&5@bebvCTc8s%AO-!0)I&j(sk)vEKU1x}Hf<|{Oq6z8t z)_c|e5*Jw|H+7(*i;aR7Z5)Lue*XGvD4f`9^}k0)QgPiLa_x5R4cBzPDYyK5Zuw;O zT$?}_+^l=wuO#XDRNO@TQ#7J*8A4d#NYz74_Qofm7>X<*x0R*D$fTK1DPN>)r;2>F zs{LZ=j!Eqqd!1Dub-ffJu_D{x&_zJEi~jh2O{)N+z=Dy*^Jhc+Jg}OlR%I&sjemrf zz)Uw8b?Ulv#|q&PY`Q#Rxlcqzp;OY0g(N(s9&vbNFGiw0@K{e)JIno82uH~6bkVV# z%x%3{aYJ3zNjRwOUQcGqP4$k3fa>~nAR}uU*JQkD&)m~f{$=6U5DPK17}Z*wy}UG) zyxy@^Jpnco5i#uQjFRFe(W0%gJP2mycV-uRk=1iG20kmL){L>1W{-b{m0Yo!Pg#4J z3;ylFuk9{R37V?g1)*@`;COjwy5y;$LF#b_t1%AO)iv4Op57;WZa6;Op>!_u#3w~_ zR)vppCAW_t@$!d>CP%7|Fy^rMrOU1`$BccX`B>BtHtg-q#!QHFUb=v`ky8;uyC-Jl zQ};SJoQQAEn9=RjJT3temPNGHi=mqaK^;S5gM^K55k{~lj2I+7+2n`s#QO&6>u>s& z*!37_+F)86)Wp;yACe8B@BnRySwA(j3W~ZO!GGR}>jSBeZXq&~zC(iDim*pZ!S4ZW z0uLK5QA5TTk{+TCO`cPq3V(~5@g9elWiETIE3l>+CZGm}M!mjPs zu7E+B2%Ey5+;$TkFUI3DzpaqTZFU7v{;n0{Mi-i5Mv_=p}1dV`${yLO z$sPL{f1F++YHdgsf65a2i-~{+-BZ6d2F%pe5vXF9rmIh-h`n9{e8j6XC>r=kaK4oY zRKjTqfyp;HT5VPYz+f?-+KbsCm`mQFBuL|=;v)FM;o-emj=>Nq{ZXwpEiapBZl_@lH5>T# zE{Ail!eLpGCoeV+2P4N#Bcmqma$a6U)w-gt;!t(V9I5G_!FmIOUDZXW0S1e%1Q`j- zQUS{O=Cjh;^^J(hx{!WSwENWfcC$(N?r6fPdTg4>=AqD>5z@rRM-abV<~7lHE(@o( zuFN_phDV7Ab3Qmkr8$OOubr+=nt>6s6nM9{E;{hd=>z56R|iz`xKr7-NwF z0}``tMc-U7NJ2syBUyGu6gvaC0KUW<(y7EG5(p!{jtbKHpigK>`#r#qy+tBUuoCmZ z62z{Bmy~woLp}Q-EI{vN-bRC<`tQ~QxfP-ep_xM6*>La^fBAx!-7(F@vi&ujO(dKdR1 z;xZT-I5-;r{$)8Hiy-~eQ%g!RL3ukJ?XUmIkV4gv3Du*wM`>{e_6y8*JzT9$u&~cu z9T;yUKQ%!`xz|xFxI1L?2j8pWs;b!+hmA5m%YAmbh zt-|4y{&mjxl9FjVAyYcd6p5&*3?`_b;DoRs?MQgRbID3%^;@Naj7p1nbE%Jc1Tb-t zhm~xlt?1PBrHu5)OI6;%Smrf#WZO%PPTNbq*9|tJ<^z{fKI*|mO=%k@M8#c`OmvIg z&Io*$_=qa4Sc|Z*Wk$}0ToZ)PM^(PT`s^yrMLlLqc~2ld;q5Iw#+TWq0N>OTk zzpLyb=0zeTM6%*lC9Z-!=~dC6D5je^kQi;w1oO|aw{u%nl1=O6RwCZ8P|9s+&JV02 zj&X#4BpRD%5la_M$V zYGJ%Q&<7TIY^ASLfv$sQVKi}}XUOqa6CwDq%I|j4Kv0-8GsX^LM@|klPgA##*Vn%| z7O;6bCCOB~`P9pnXGbD6kD>-F#RIMk_;2wM)&C49KBQ>ZU<1)Fl|)2RbrSPDZ@d7P zQSC(U-Pimd=S53u2}1rR447;o@CZ7<)*&#%tMRFLKhKgGQm^0ZhK2y;kNl{G2KiAD z*2NSM&4(A!EYc-AUF^k`vnCJONj_i#BhYKY8(LY5$??d>*qGCrSFtyYgMDS<)}fmR z5n=%ci*$}33unOJ`OP++FwfqKMqCl^PU{}01=_dtmpEjqQ@+0c_>JFpyo3x&np-NJFpX&Zg2s-mDaY14+QSi7jgU6kPK|!xyR-q7B1xa%@_cM>@ zgP`?dZin3||8q;84=f$SE{PTvK^xejTfelvia_~fDk+{Ba}CyA=6_{cqHRgv?`Uz` zBz3v$t}-_`N5`ca+sLR?11prF8{ne1cG=ba9{8dgz~?9gT86+`S@5%j(9JYnDty@% zwxpoNDv2g=FF12DtT3w>{s5HS;}sO`?Q99c%dygFxA$2gw`>TPO8v-!gu168Hb#MK zJ6Z_CF4fP+wt21>(eE5P@Fowxc(9hVvtZuRd5+DH9KL*qg-Mz<#dJ!wHv%WT4@ce{ zg1m4q*x5vGQoJ(I4;5C8P9+*5q+IoD?0`e&yGXRwkEp>^0tE{5EtnbX;Hf&$hekHm zaBXMvXr)|3lX{Tr-XF^*U)!kovQ=l5jo3StF?Q9500Y8|K?!)oj%;x2OT4I*Ym@nU zY++&~>jy3nks~IsbkYRbZHfgSwFH9^HLTW@g0$t(F+vNOYsX+r6yJ3ds$nwF(?ejg zfPSjUvPB4;IfkZ%q;pp2W&r-!NfCEu0$T7lwMda2-<&CIus6?OyX6`TENp6*(pr{*&J2JPi zngNa?(c~}$v0=Yq|9d1q5vE3>;`X2>DuRj$I3$^WcSz$97D3Lv@6YS9v*;(*=q3-K z)5xUM9bHC@0fQfyp09toM|oI*bSf^0fgl+cS>-R&^k`nm>8x@j$Sn3`+-0h_kQp_* zHeDdjFYM`pp)gw}xmsxC3a_4NEwmd^CApp!<9&PQXtt53LZJHDmu$e|8UrUMxQoM} z{6>gQ9y(dR`YtV-Pn~+NY%g5ic9Mj3xbGl2yE3y?BIH|O1lRn<7%JwXi;xj0RNozS z6RQd@IanAi5tkf%wgVaGmj>J+H4Xjf&SMfqppGWQe*B)NbpMJo-EIQ z=a59d|8Yo`@smtSM|$DCspgG^{Ckd(THswd z;G~cJ;;f3>0nKXKq(gf>+QQ-X+c;uCJ2d zsT4S7{0>9y@u|%Q#Y%OHYCcNj9150XT`Frt`5N z)}e;m)oA`-ol>Q8^&pxkh2&Q2Vz|Z0NG`5Ri2cK1`cgNa~^KpELGrsiC84(R8OzoetB-; zS9EofNX)+iqZ=Qda{n3NP(F8#sko`mn|=xf12+3d0`Mraq8c{pRFU{A5kNicKQ(yI zWOnaSgma39RaD}lWD3*_IG>Au9CBpl_(!stO(W&e>D`L7Wx7i=c; z1;d zuqC0ftTS^@AQAIjsj&2){;Y57FO&&jY+j6=#rk_K`V4Nf7>4JBfUN}Tm{c^wYF9)g zyH5$+xqlYZcOSY{YRTz+3a^B@a{R7$oA* zRL?BbnmFJqUYz4F(dT7TGNC^G`cT*`lAqAz-6HvIY|~UzreWqna!YfBs|v3^4Vj|q zFwRFCimT=`B9J}y%1o4=1nB;H%KI&SM8Q6$%1W3~JsRLv&IQw#Ke5d$cis%B!HA#A ziy9F0XGu}6)jY!aeRQav~6=s&Bp-?M;zg>;P-5^#MPwV{!1FV08afMIokhmUaMu%8>}Ea zZ^l0C#kPIXVpFJUoLo;VPNra|10nfpUB8s2uz^R-QZl(cgD`EInU#)XOHNuJ9pjQ( zxV-nURPJ!^mzpER7rz)4I$U`u0(y7c8E-ca$sMf?0b5tT zx)+n^dcBt9in4UxM_IbMY~B|&&?QKMJiV8@)D?b31V%W;%j~8kovzK1{ZM6Med(sQXwp=t1Q;axxA0I_jKt)! z_F7F@VAf!cML(e!w8K(;iSh@W95Ak|FIsRa{Fu*2&^sY}7Z?pu+#e{6aWQW5H~4;# zI5=8|3t-OVq{L=>kLSn7%s1CB-YuxAE}?#DSwnF!*vKR_*Zn6W)(FIZ)jh87IRVm9gIiIF@8 z)1J$TaFp|hJkfn12G(e$?c0Cn6XbsCUDfs7E7@e9OzvrDM~6_te6htF$ePP)2zMB| zs}!A&T2#v_;y4C$Oq=*E?210G-8*@t!(;62N}%^Mpg`SQ@Qch$QV2uLe28STCNDwa2CT=GiudL6&n$+BW0o3{f< zD10hXMe^75x9N6ehYA>`9bKQodL}Om@>Q)>%Cr8g&HRvnZ*y{I})x?<7Yz&_(C#e@Sh=>vjo9 ziO9u6JyAjYwYU<&k?%7kPIdJQcI$m);xVCme6!FaP7@!+l#pT5)P6|&Otki&OQtkbI{oAjZZJ)?y~KAqO^E{h*;aY2xx+_m_}Qmk}@rRLNh zruGPiPc1f;M#BEt@=_K-?V$vcn@D|(w9m7)SJ9*^18}`#pC*m*Y?MUqpd5fq3bU8X_d}qGDu{3h(DY3;ROi z0C{XLjq}cBwxniK)8(kyFP<6-mJX>wLqX3`9gtKUA9%cK%@aGn_dp!G-r>#ULL%mV zo4g|Bvtu2#WU_{;x*&^)!TVJ{tmhqavd8~4LcqfLGS9Kl(_4Vb|2tcDm@LL~pshM5 zrE=;~+T0Thb^dI4O*h*#P(Tuvhpwp9t5l}GRk`*?vs!=cgmSl+D;Ww2x(y<+C5VU* z6@w2qW3j2YecfwB9a+0zL^>1|7guCau4X2ts4Gq9u~H%5Hwdy=Gg4CHkxlVwB*Dw&VH)& zfWcX4C}+{WH7uf{%~T6kxlDT9EYTdyGE>xR{{Ql-|4ZCBZp!kTHTTwelAtJB#gIs{ zwxZMALv}3kZ|}(Fjn3l(*a~Lh-ykTc^(mIa1+=t#BPo2(%Tlpw+Cx5E>Az2^VQ@`t?5VC#&p-HJ*dP$^Wt7H-NNIGx%^pcsMxKRVIfq@L!zQ{oP)D zF4YMxQEw5v3;2lA*HYiUCx*|yp79KdP#IIm;_QTPj!*i*gn1((VhU)U8zTg{)tbO%k5kN$f1#H@q#2Cy~Fmv=<|?9C6V)fqTDS&o@B zz>S3oP3j_QqIC)XNee7EDQr+P?5iyg{?Y@~QZ;bi|L3E;xJ7XN(On1DdoN-nhHs_* z-aW4p-`2rVklY}IfAfO$q3JRIvGsqpM~H)ksnJ0}fP=+JuD~14Idpzmvv4FO#sF>Y=r;- diff --git a/prototype/etc/prototype.ucls b/prototype/etc/prototype.ucls deleted file mode 100644 index 6d19fdc23..000000000 --- a/prototype/etc/prototype.ucls +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/prototype/etc/prototype.urm.puml b/prototype/etc/prototype.urm.puml deleted file mode 100644 index 801679fb7..000000000 --- a/prototype/etc/prototype.urm.puml +++ /dev/null @@ -1,82 +0,0 @@ -@startuml -package com.iluwatar.prototype { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - abstract class Beast { - + Beast() - + clone() : Beast {abstract} - } - class ElfBeast { - + ElfBeast() - + clone() : Beast - + toString() : String - } - class ElfMage { - + ElfMage() - + clone() : Mage - + toString() : String - } - class ElfWarlord { - + ElfWarlord() - + clone() : Warlord - + toString() : String - } - interface HeroFactory { - + createBeast() : Beast {abstract} - + createMage() : Mage {abstract} - + createWarlord() : Warlord {abstract} - } - class HeroFactoryImpl { - - beast : Beast - - mage : Mage - - warlord : Warlord - + HeroFactoryImpl(mage : Mage, warlord : Warlord, beast : Beast) - + createBeast() : Beast - + createMage() : Mage - + createWarlord() : Warlord - } - abstract class Mage { - + Mage() - + clone() : Mage {abstract} - } - class OrcBeast { - + OrcBeast() - + clone() : Beast - + toString() : String - } - class OrcMage { - + OrcMage() - + clone() : Mage - + toString() : String - } - class OrcWarlord { - + OrcWarlord() - + clone() : Warlord - + toString() : String - } - abstract class Prototype { - + Prototype() - + clone() : Object {abstract} - } - abstract class Warlord { - + Warlord() - + clone() : Warlord {abstract} - } -} -HeroFactoryImpl --> "-beast" Beast -HeroFactoryImpl --> "-warlord" Warlord -HeroFactoryImpl --> "-mage" Mage -Beast --|> Prototype -ElfBeast --|> Beast -ElfMage --|> Mage -ElfWarlord --|> Warlord -HeroFactoryImpl ..|> HeroFactory -Mage --|> Prototype -OrcBeast --|> Beast -OrcMage --|> Mage -OrcWarlord --|> Warlord -Warlord --|> Prototype -@enduml \ No newline at end of file diff --git a/prototype/etc/prototype_1.png b/prototype/etc/prototype_1.png deleted file mode 100644 index 8b513c8d20f3dc21ad8377e041223e9b554c79ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97668 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

      NDS-aRNdDlf;n|O{E&gm- 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 Mtg1`};!)852fNqrh5!Hn From 2a7feba427873136bb96c6dbdeb3ee11d6374718 Mon Sep 17 00:00:00 2001 From: "mahendran.mookkiah" Date: Fri, 18 Aug 2017 14:18:43 -0400 Subject: [PATCH 338/492] #587 SonarQube reports bugs As recommended in https://sonarcloud.io/organizations/default/rules#rule_key=squid%3AS2274 Used while insteadof if - for waiting upon a condition. --- .../iluwatar/async/method/invocation/ThreadAsyncExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java index f92792c39..d12ebbe19 100644 --- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java +++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java @@ -139,7 +139,7 @@ public class ThreadAsyncExecutor implements AsyncExecutor { @Override public void await() throws InterruptedException { synchronized (lock) { - if (!isCompleted()) { + while (!isCompleted()) { lock.wait(); } } From 51751ec821edba15c59649ca7a594e4e517c47f1 Mon Sep 17 00:00:00 2001 From: "mahendran.mookkiah" Date: Fri, 18 Aug 2017 20:44:28 -0400 Subject: [PATCH 339/492] #587 SonarQube reports bugs reader-writer-lock and refactor Keeping wait() calls with in synchronized block closely to adhere SonarQube rules. Avoid nested synchronized block by extracting method. Added writing and reading time to simulate testing to ensure 1) writers are waiting for globalMutex to be empty 2) readers to confirm there is no writers. --- .../com/iluwatar/reader/writer/lock/App.java | 40 ++++++-- .../iluwatar/reader/writer/lock/Reader.java | 33 +++++-- .../reader/writer/lock/ReaderWriterLock.java | 96 ++++++++----------- .../iluwatar/reader/writer/lock/Writer.java | 33 +++++-- .../writer/lock/utils/InMemoryAppender.java | 2 +- 5 files changed, 128 insertions(+), 76 deletions(-) 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 index af7b5df2c..42335f313 100644 --- 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 @@ -23,14 +23,15 @@ package com.iluwatar.reader.writer.lock; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * * In a multiple thread applications, the threads may try to synchronize the shared resources @@ -62,21 +63,42 @@ public class App { ExecutorService executeService = Executors.newFixedThreadPool(10); ReaderWriterLock lock = new ReaderWriterLock(); - - // Start 5 readers + + // Start writers IntStream.range(0, 5) - .forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock()))); + .forEach(i -> executeService.submit(new Writer("Writer " + i, lock.writeLock(), + ThreadLocalRandom.current().nextLong(5000)))); + LOGGER.info("Writers added..."); - // Start 5 writers + // Start readers IntStream.range(0, 5) - .forEach(i -> executeService.submit(new Writer("Writer " + i, lock.writeLock()))); + .forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(), + ThreadLocalRandom.current().nextLong(10)))); + 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 + IntStream.range(6, 10) + .forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(), + ThreadLocalRandom.current().nextLong(10)))); + 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"); + 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 index 006aff7d7..b0ccecaba 100644 --- 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 @@ -22,11 +22,11 @@ */ package com.iluwatar.reader.writer.lock; +import java.util.concurrent.locks.Lock; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.locks.Lock; - /** * Reader class, read when it acquired the read lock */ @@ -37,10 +37,30 @@ public class Reader implements Runnable { private Lock readLock; private String name; + + private long readingTime; - public Reader(String name, Lock readLock) { + /** + * 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 @@ -49,7 +69,8 @@ public class Reader implements Runnable { try { read(); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.info("InterruptedException when reading", e); + Thread.currentThread().interrupt(); } finally { readLock.unlock(); } @@ -61,7 +82,7 @@ public class Reader implements Runnable { */ public void read() throws InterruptedException { LOGGER.info("{} begin", name); - Thread.sleep(250); - LOGGER.info("{} finish", 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 index e7b3c4451..b377b2273 100644 --- 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 @@ -29,13 +29,18 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * 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. + * 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. */ public class ReaderWriterLock implements ReadWriteLock { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReaderWriterLock.class); private Object readerMutex = new Object(); @@ -45,10 +50,10 @@ public class ReaderWriterLock implements ReadWriteLock { /** * 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. + * 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. */ @@ -74,13 +79,6 @@ public class ReaderWriterLock implements ReadWriteLock { return globalMutex.contains(writerLock); } - /** - * return true when globalMutex hold the reference of readerLock - */ - private boolean doesReaderOwnThisLock() { - return globalMutex.contains(readerLock); - } - /** * Nobody get the lock when globalMutex contains nothing * @@ -89,14 +87,6 @@ public class ReaderWriterLock implements ReadWriteLock { return globalMutex.isEmpty(); } - private static void waitUninterruptibly(Object o) { - try { - o.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - /** * Reader Lock, can be access for more than one reader concurrently if no writer get the lock */ @@ -104,31 +94,35 @@ public class ReaderWriterLock implements ReadWriteLock { @Override public void lock() { - synchronized (readerMutex) { - currentReaderCount++; if (currentReaderCount == 1) { - // Try to get the globalMutex lock for the first reader - synchronized (globalMutex) { - while (true) { - // 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. - if (isLockFree() || doesReaderOwnThisLock()) { - globalMutex.add(this); - break; - } else { - // If lock is acquired by the write, let the thread wait until the writer release - // the lock - waitUninterruptibly(globalMutex); - } - } - } - + 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) { + LOGGER.info("InterruptedException while waiting for globalMutex in acquireForReaders", e); + Thread.currentThread().interrupt(); + } + } + globalMutex.add(this); + } + } + @Override public void unlock() { @@ -179,23 +173,17 @@ public class ReaderWriterLock implements ReadWriteLock { synchronized (globalMutex) { - while (true) { - // When there is no one acquired the lock, just put the writeLock reference to the - // globalMutex to indicate that the lock is acquired by one writer. - // It is ensure that writer can only get the lock when no reader/writer acquired the lock. - if (isLockFree()) { - globalMutex.add(this); - break; - } else if (doesWriterOwnThisLock()) { - // Wait when other writer get the lock - waitUninterruptibly(globalMutex); - } else if (doesReaderOwnThisLock()) { - // Wait when other reader get the lock - waitUninterruptibly(globalMutex); - } else { - throw new AssertionError("it should never reach here"); + // 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); } } 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 index c468a61f8..dc379eef9 100644 --- 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 @@ -22,11 +22,11 @@ */ package com.iluwatar.reader.writer.lock; +import java.util.concurrent.locks.Lock; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.locks.Lock; - /** * Writer class, write when it acquired the write lock */ @@ -37,10 +37,30 @@ public class Writer implements Runnable { private Lock writeLock; private String name; + + private 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; } @@ -50,18 +70,19 @@ public class Writer implements Runnable { try { write(); } catch (InterruptedException e) { - e.printStackTrace(); + 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(250); - LOGGER.info("{} finish", 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/utils/InMemoryAppender.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java index 30624a650..b8ad531ce 100644 --- 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 @@ -52,6 +52,6 @@ public class InMemoryAppender extends AppenderBase { } public boolean logContains(String message) { - return log.stream().anyMatch(event -> event.getFormattedMessage().equals(message)); + return log.stream().anyMatch(event -> event.getFormattedMessage().contains(message)); } } From fbf5ffe67a63ddb43f003efeb6a1fc81bdf05ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 19 Aug 2017 10:00:18 +0300 Subject: [PATCH 340/492] #590 Add explanation for Adapter --- adapter/README.md | 82 +++++++++++++++++- adapter/etc/adapter.png | Bin 12086 -> 0 bytes adapter/etc/adapter.ucls | 70 --------------- adapter/etc/adapter.urm.puml | 37 -------- .../main/java/com/iluwatar/adapter/App.java | 14 +-- .../java/com/iluwatar/adapter/Captain.java | 27 +++--- .../com/iluwatar/adapter/FishingBoat.java | 9 +- ...shingBoat.java => FishingBoatAdapter.java} | 20 ++--- .../{BattleShip.java => RowingBoat.java} | 8 +- .../iluwatar/adapter/AdapterPatternTest.java | 29 +++---- pom.xml | 1 + 11 files changed, 121 insertions(+), 176 deletions(-) delete mode 100644 adapter/etc/adapter.png delete mode 100644 adapter/etc/adapter.ucls delete mode 100644 adapter/etc/adapter.urm.puml rename adapter/src/main/java/com/iluwatar/adapter/{BattleFishingBoat.java => FishingBoatAdapter.java} (70%) rename adapter/src/main/java/com/iluwatar/adapter/{BattleShip.java => RowingBoat.java} (92%) diff --git a/adapter/README.md b/adapter/README.md index 4059ea852..6de04a72c 100644 --- a/adapter/README.md +++ b/adapter/README.md @@ -19,10 +19,85 @@ Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. -![alt text](./etc/adapter.png "Adapter") +## Explanation -## General usage of Adapter Pattern: -+ Wrappers used to adopt 3rd parties libraries and frameworks - most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code. +Real world example + +> Consider that you have some pictures in your memory card and you need to transfer them to your computer. In order to transfer them you need some kind of adapter that is compatible with your computer ports so that you can attach memory card to your computer. In this case card reader is an adapter. +> Another example would be the famous power adapter; a three legged plug can't be connected to a two pronged outlet, it needs to use a power adapter that makes it compatible with the two pronged outlet. +> Yet another example would be a translator translating words spoken by one person to another + +In plain words + +> Adapter pattern lets you wrap an otherwise incompatible object in an adapter to make it compatible with another class. + +Wikipedia says + +> In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code. + +**Programmatic Example** + +Consider a captain that can only use rowing boats and cannot sail at all. + +First we have interfaces `RowingBoat` and `FishingBoat` + +``` +public interface RowingBoat { + void row(); +} + +public class FishingBoat { + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class); + public void sail() { + LOGGER.info("The fishing boat is sailing"); + } +} +``` + +And captain expects an implementation of `RowingBoat` interface to be able to move + +``` +public class Captain implements RowingBoat { + + private RowingBoat rowingBoat; + + public Captain(RowingBoat rowingBoat) { + this.rowingBoat = rowingBoat; + } + + @Override + public void row() { + rowingBoat.row(); + } +} +``` + +Now let's say the pirates are coming and our captain needs to escape but there is only fishing boat available. We need to create an adapter that allows the captain to operate the fishing boat with his rowing boat skills. + +``` +public class FishingBoatAdapter implements RowingBoat { + + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class); + + private FishingBoat boat; + + public FishingBoatAdapter() { + boat = new FishingBoat(); + } + + @Override + public void row() { + boat.sail(); + } +} +``` + +And now the `Captain` can use the `FishingBoat` to escape the pirates. + +``` +Captain captain = new Captain(new FishingBoatAdapter()); +captain.row(); +``` ## Applicability Use the Adapter pattern when @@ -30,6 +105,7 @@ Use the Adapter pattern when * you want to use an existing class, and its interface does not match the one you need * you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces * you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class. +* most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code. ## Consequences: Class and object adapters have different trade-offs. A class adapter diff --git a/adapter/etc/adapter.png b/adapter/etc/adapter.png deleted file mode 100644 index f43358b042e73edcbcb9589e540a8d306fa1d6c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12086 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 diff --git a/adapter/etc/adapter.ucls b/adapter/etc/adapter.ucls deleted file mode 100644 index 290ff544e..000000000 --- a/adapter/etc/adapter.ucls +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/adapter/etc/adapter.urm.puml b/adapter/etc/adapter.urm.puml deleted file mode 100644 index 847427a44..000000000 --- a/adapter/etc/adapter.urm.puml +++ /dev/null @@ -1,37 +0,0 @@ -@startuml -package com.iluwatar.adapter { - class App { - + App() - + main(args : String[]) {static} - } - class BattleFishingBoat { - - LOGGER : Logger {static} - - boat : FishingBoat - + BattleFishingBoat() - + fire() - + move() - } - interface BattleShip { - + fire() {abstract} - + move() {abstract} - } - class Captain { - - battleship : BattleShip - + Captain() - + Captain(battleship : BattleShip) - + fire() - + move() - + setBattleship(battleship : BattleShip) - } - class FishingBoat { - - LOGGER : Logger {static} - + FishingBoat() - + fish() - + sail() - } -} -BattleFishingBoat --> "-boat" FishingBoat -Captain --> "-battleship" BattleShip -BattleFishingBoat ..|> BattleShip -Captain ..|> BattleShip -@enduml \ No newline at end of file diff --git a/adapter/src/main/java/com/iluwatar/adapter/App.java b/adapter/src/main/java/com/iluwatar/adapter/App.java index 239424da9..a624cc38f 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/App.java +++ b/adapter/src/main/java/com/iluwatar/adapter/App.java @@ -34,14 +34,14 @@ package com.iluwatar.adapter; * object. This example uses the object adapter approach. * *

      - * The Adapter ({@link BattleFishingBoat}) converts the interface of the adaptee class ( - * {@link FishingBoat}) into a suitable one expected by the client ( {@link BattleShip} ). + * The Adapter ({@link FishingBoatAdapter}) converts the interface of the adaptee class ( + * {@link FishingBoat}) into a suitable one expected by the client ( {@link RowingBoat} ). * *

      * The story of this implementation is this.
      - * Pirates are coming! we need a {@link BattleShip} to fight! We have a {@link FishingBoat} and our + * Pirates are coming! we need a {@link RowingBoat} to flee! We have a {@link FishingBoat} and our * captain. We have no time to make up a new ship! we need to reuse this {@link FishingBoat}. The - * captain needs a battleship which can fire and move. The spec is in {@link BattleShip}. We will + * captain needs a rowing boat which he can operate. The spec is in {@link RowingBoat}. We will * use the Adapter pattern to reuse {@link FishingBoat}. * */ @@ -53,8 +53,8 @@ public class App { * @param args command line args */ public static void main(String[] args) { - Captain captain = new Captain(new BattleFishingBoat()); - captain.move(); - captain.fire(); + // The captain can only operate rowing boats but with adapter he is able to use fishing boats as well + Captain captain = new Captain(new FishingBoatAdapter()); + captain.row(); } } diff --git a/adapter/src/main/java/com/iluwatar/adapter/Captain.java b/adapter/src/main/java/com/iluwatar/adapter/Captain.java index 6d88b1975..369016980 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/Captain.java +++ b/adapter/src/main/java/com/iluwatar/adapter/Captain.java @@ -23,33 +23,26 @@ package com.iluwatar.adapter; /** - * The Captain uses {@link BattleShip} to fight.
      + * The Captain uses {@link RowingBoat} to sail.
      * This is the client in the pattern. */ -public class Captain implements BattleShip { +public class Captain implements RowingBoat { - private BattleShip battleship; + private RowingBoat rowingBoat; - public Captain() { + public Captain() {} + public Captain(RowingBoat rowingBoat) { + this.rowingBoat = rowingBoat; } - public Captain(BattleShip battleship) { - this.battleship = battleship; - } - - public void setBattleship(BattleShip battleship) { - this.battleship = battleship; + public void setRowingBoat(RowingBoat rowingBoat) { + this.rowingBoat = rowingBoat; } @Override - public void fire() { - battleship.fire(); - } - - @Override - public void move() { - battleship.move(); + public void row() { + rowingBoat.row(); } } diff --git a/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java index 2124d9d9f..c46814d18 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java +++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java @@ -27,7 +27,8 @@ import org.slf4j.LoggerFactory; /** * - * Device class (adaptee in the pattern). We want to reuse this class + * Device class (adaptee in the pattern). We want to reuse this class. + * Fishing boat moves by sailing. * */ public class FishingBoat { @@ -35,11 +36,7 @@ public class FishingBoat { private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class); public void sail() { - LOGGER.info("The Boat is moving to that place"); - } - - public void fish() { - LOGGER.info("fishing ..."); + LOGGER.info("The fishing boat is sailing"); } } diff --git a/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java similarity index 70% rename from adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java rename to adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java index 5e4da91f8..c94932b2b 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java +++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java @@ -27,30 +27,22 @@ import org.slf4j.LoggerFactory; /** * - * Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link BattleShip} - * interface expected by the client ({@link Captain}).
      - * In this case we added a new function fire to suit the interface. We are reusing the - * {@link FishingBoat} without changing itself. The Adapter class can just map the functions of the - * Adaptee or add, delete features of the Adaptee. + * Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link RowingBoat} + * interface expected by the client ({@link Captain}). * */ -public class BattleFishingBoat implements BattleShip { +public class FishingBoatAdapter implements RowingBoat { - private static final Logger LOGGER = LoggerFactory.getLogger(BattleFishingBoat.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class); private FishingBoat boat; - public BattleFishingBoat() { + public FishingBoatAdapter() { boat = new FishingBoat(); } @Override - public void fire() { - LOGGER.info("fire!"); - } - - @Override - public void move() { + public void row() { boat.sail(); } } diff --git a/adapter/src/main/java/com/iluwatar/adapter/BattleShip.java b/adapter/src/main/java/com/iluwatar/adapter/RowingBoat.java similarity index 92% rename from adapter/src/main/java/com/iluwatar/adapter/BattleShip.java rename to adapter/src/main/java/com/iluwatar/adapter/RowingBoat.java index 62ee366e7..a9ca9ad39 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/BattleShip.java +++ b/adapter/src/main/java/com/iluwatar/adapter/RowingBoat.java @@ -24,13 +24,11 @@ package com.iluwatar.adapter; /** * The interface expected by the client.
      - * A Battleship can fire and move. + * A rowing boat is rowed to move. * */ -public interface BattleShip { +public interface RowingBoat { - void fire(); - - void move(); + void row(); } diff --git a/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java index 89c9bc5d5..9938f0559 100644 --- a/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java +++ b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java @@ -39,9 +39,9 @@ public class AdapterPatternTest { private Map beans; - private static final String BATTLESHIP_BEAN = "engineer"; + private static final String FISHING_BEAN = "fisher"; - private static final String CAPTAIN_BEAN = "captain"; + private static final String ROWING_BEAN = "captain"; /** * This method runs before the test execution and sets the bean objects in the beans Map. @@ -50,34 +50,29 @@ public class AdapterPatternTest { public void setup() { beans = new HashMap<>(); - BattleFishingBoat battleFishingBoat = spy(new BattleFishingBoat()); - beans.put(BATTLESHIP_BEAN, battleFishingBoat); + FishingBoatAdapter fishingBoatAdapter = spy(new FishingBoatAdapter()); + beans.put(FISHING_BEAN, fishingBoatAdapter); Captain captain = new Captain(); - captain.setBattleship((BattleFishingBoat) beans.get(BATTLESHIP_BEAN)); - beans.put(CAPTAIN_BEAN, captain); + captain.setRowingBoat((FishingBoatAdapter) beans.get(FISHING_BEAN)); + beans.put(ROWING_BEAN, captain); } /** - * This test asserts that when we use the move() method on a captain bean(client), it is - * internally calling move method on the battleship object. The Adapter ({@link BattleFishingBoat} + * This test asserts that when we use the row() method on a captain bean(client), it is + * internally calling sail method on the fishing boat object. The Adapter ({@link FishingBoatAdapter} * ) converts the interface of the target class ( {@link FishingBoat}) into a suitable one * expected by the client ({@link Captain} ). */ @Test public void testAdapter() { - BattleShip captain = (BattleShip) beans.get(CAPTAIN_BEAN); + RowingBoat captain = (RowingBoat) beans.get(ROWING_BEAN); // when captain moves - captain.move(); + captain.row(); // the captain internally calls the battleship object to move - BattleShip battleship = (BattleShip) beans.get(BATTLESHIP_BEAN); - verify(battleship).move(); - - // same with above with firing - captain.fire(); - verify(battleship).fire(); - + RowingBoat adapter = (RowingBoat) beans.get(FISHING_BEAN); + verify(adapter).row(); } } diff --git a/pom.xml b/pom.xml index 992537f9b..347a6bc15 100644 --- a/pom.xml +++ b/pom.xml @@ -466,6 +466,7 @@ abstract-factory builder prototype + adapter From 5db6776971094dc4e67287cc735c3e47a0dbfb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 19 Aug 2017 10:10:49 +0300 Subject: [PATCH 341/492] #590 Fix PMD issue --- .../main/java/com/iluwatar/adapter/FishingBoatAdapter.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java index c94932b2b..1e758e917 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java +++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java @@ -22,9 +22,6 @@ */ package com.iluwatar.adapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * * Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link RowingBoat} @@ -33,8 +30,6 @@ import org.slf4j.LoggerFactory; */ public class FishingBoatAdapter implements RowingBoat { - private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class); - private FishingBoat boat; public FishingBoatAdapter() { From ed1a0022b9875dd8b168bd48eded37218940f103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 19 Aug 2017 11:00:34 +0300 Subject: [PATCH 342/492] #596 Add more logging to Reactor --- .../java/com/iluwatar/reactor/app/AppClient.java | 10 ++++++---- .../com/iluwatar/reactor/framework/NioReactor.java | 5 +++-- .../java/com/iluwatar/reactor/app/ReactorTest.java | 13 +++++++++++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java index 4db4f5e2a..446628769 100644 --- a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java +++ b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java @@ -65,6 +65,7 @@ public class AppClient { * @throws IOException if any I/O error occurs. */ public void start() throws IOException { + LOGGER.info("Starting logging clients"); service.execute(new TcpLoggingClient("Client 1", 6666)); service.execute(new TcpLoggingClient("Client 2", 6667)); service.execute(new UdpLoggingClient("Client 3", 6668)); @@ -81,16 +82,17 @@ public class AppClient { try { service.awaitTermination(1000, TimeUnit.SECONDS); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("exception awaiting termination", e); } } + LOGGER.info("Logging clients stopped"); } private static void artificialDelayOf(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("sleep interrupted", e); } } @@ -119,7 +121,7 @@ public class AppClient { PrintWriter writer = new PrintWriter(outputStream); sendLogRequests(writer, socket.getInputStream()); } catch (IOException e) { - e.printStackTrace(); + LOGGER.error("error sending requests", e); throw new RuntimeException(e); } } @@ -185,7 +187,7 @@ public class AppClient { artificialDelayOf(100); } } catch (IOException e1) { - e1.printStackTrace(); + LOGGER.error("error sending packets", e1); } } } diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java index bc5b27494..a315389a3 100644 --- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java @@ -94,7 +94,7 @@ public class NioReactor { LOGGER.info("Reactor started, waiting for events..."); eventLoop(); } catch (IOException e) { - e.printStackTrace(); + LOGGER.error("exception in event loop", e); } }); } @@ -112,6 +112,7 @@ public class NioReactor { selector.wakeup(); reactorMain.awaitTermination(4, TimeUnit.SECONDS); selector.close(); + LOGGER.info("Reactor stopped"); } /** @@ -206,7 +207,7 @@ public class NioReactor { try { key.channel().close(); } catch (IOException e1) { - e1.printStackTrace(); + LOGGER.error("error closing channel", e1); } } } diff --git a/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java b/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java index 413bbc017..7aa80f8cc 100644 --- a/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java +++ b/reactor/src/test/java/com/iluwatar/reactor/app/ReactorTest.java @@ -24,10 +24,13 @@ package com.iluwatar.reactor.app; import java.io.IOException; +import com.iluwatar.reactor.framework.NioReactor; import org.junit.Test; import com.iluwatar.reactor.framework.SameThreadDispatcher; import com.iluwatar.reactor.framework.ThreadPoolDispatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @@ -36,6 +39,8 @@ import com.iluwatar.reactor.framework.ThreadPoolDispatcher; */ public class ReactorTest { + private static final Logger LOGGER = LoggerFactory.getLogger(ReactorTest.class); + /** * Test the application using pooled thread dispatcher. * @@ -44,6 +49,7 @@ public class ReactorTest { */ @Test public void testAppUsingThreadPoolDispatcher() throws IOException, InterruptedException { + LOGGER.info("testAppUsingThreadPoolDispatcher start"); App app = new App(new ThreadPoolDispatcher(2)); app.start(); @@ -54,12 +60,13 @@ public class ReactorTest { try { Thread.sleep(2000); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("sleep interrupted", e); } client.stop(); app.stop(); + LOGGER.info("testAppUsingThreadPoolDispatcher stop"); } /** @@ -70,6 +77,7 @@ public class ReactorTest { */ @Test public void testAppUsingSameThreadDispatcher() throws IOException, InterruptedException { + LOGGER.info("testAppUsingSameThreadDispatcher start"); App app = new App(new SameThreadDispatcher()); app.start(); @@ -80,11 +88,12 @@ public class ReactorTest { try { Thread.sleep(2000); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("sleep interrupted", e); } client.stop(); app.stop(); + LOGGER.info("testAppUsingSameThreadDispatcher stop"); } } From 82d7e57e8eb8a425f5af87bc33ed850ec72f382b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20Hamzao=C4=9Fullar=C4=B1?= Date: Sat, 19 Aug 2017 22:06:35 +0300 Subject: [PATCH 343/492] Integration Test --- event-sourcing/etc/event-sourcing.ucls | 4 +- .../{service => }/AccountService.java | 4 +- .../MoneyTransactionService.java | 4 +- .../{service => }/SequenceIdGenerator.java | 4 +- .../event/sourcing/api/DomainEvent.java | 2 +- .../event/sourcing/api/EventProcessor.java | 2 +- .../event/sourcing/api/ProcessorJournal.java | 2 +- .../com/iluwatar/event/sourcing/app/App.java | 66 ++++++---- .../event/sourcing/domain/Account.java | 2 +- .../event/sourcing/domain/Transaction.java | 2 +- .../sourcing/event/AccountCreateEvent.java | 2 +- .../sourcing/event/MoneyDepositEvent.java | 2 +- .../sourcing/event/MoneyTransferEvent.java | 2 +- .../sourcing/event/MoneyWithdrawalEvent.java | 2 +- .../gateway/AccountCreateContractSender.java | 2 +- .../event/sourcing/gateway/Gateways.java | 2 +- .../sourcing/gateway/TransactionLogger.java | 2 +- .../sourcing/journal/JsonFileJournal.java | 2 +- .../processor/DomainEventProcessor.java | 2 +- .../sourcing/state/AccountAggregate.java | 2 +- .../event/sourcing/IntegrationTest.java | 115 ++++++++++++++++++ 21 files changed, 181 insertions(+), 46 deletions(-) rename event-sourcing/src/main/java/com/iluwatar/event/sourcing/{service => }/AccountService.java (95%) rename event-sourcing/src/main/java/com/iluwatar/event/sourcing/{service => }/MoneyTransactionService.java (97%) rename event-sourcing/src/main/java/com/iluwatar/event/sourcing/{service => }/SequenceIdGenerator.java (94%) create mode 100644 event-sourcing/src/main/test/java/com/iluwatar/event/sourcing/IntegrationTest.java diff --git a/event-sourcing/etc/event-sourcing.ucls b/event-sourcing/etc/event-sourcing.ucls index d187b1bb0..e6944ef70 100644 --- a/event-sourcing/etc/event-sourcing.ucls +++ b/event-sourcing/etc/event-sourcing.ucls @@ -122,7 +122,7 @@ - @@ -132,7 +132,7 @@ - diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/AccountService.java similarity index 95% rename from event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java rename to event-sourcing/src/main/java/com/iluwatar/event/sourcing/AccountService.java index 59cefaaee..2d6f585a5 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/AccountService.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/AccountService.java @@ -20,14 +20,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.event.sourcing.service; +package com.iluwatar.event.sourcing; import com.iluwatar.event.sourcing.api.EventProcessor; import com.iluwatar.event.sourcing.event.AccountCreateEvent; import java.util.Date; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class AccountService { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/MoneyTransactionService.java similarity index 97% rename from event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java rename to event-sourcing/src/main/java/com/iluwatar/event/sourcing/MoneyTransactionService.java index 5f7c0e9c7..0e3cb67bd 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/MoneyTransactionService.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/MoneyTransactionService.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.event.sourcing.service; +package com.iluwatar.event.sourcing; import com.iluwatar.event.sourcing.api.EventProcessor; import com.iluwatar.event.sourcing.event.MoneyDepositEvent; @@ -30,7 +30,7 @@ import java.math.BigDecimal; import java.util.Date; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class MoneyTransactionService { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/SequenceIdGenerator.java similarity index 94% rename from event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java rename to event-sourcing/src/main/java/com/iluwatar/event/sourcing/SequenceIdGenerator.java index 6e1730679..c928a8737 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/service/SequenceIdGenerator.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/SequenceIdGenerator.java @@ -20,10 +20,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.event.sourcing.service; +package com.iluwatar.event.sourcing; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class SequenceIdGenerator { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java index 693ea1755..6eb5141a2 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java @@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.api; import java.io.Serializable; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public abstract class DomainEvent implements Serializable { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java index afa218939..512f9d7f8 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java @@ -23,7 +23,7 @@ package com.iluwatar.event.sourcing.api; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public interface EventProcessor { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java index 8814b82d9..2212580dc 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java @@ -23,7 +23,7 @@ package com.iluwatar.event.sourcing.api; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public interface ProcessorJournal { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java index f62cebb62..77be00cf6 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/app/App.java @@ -24,62 +24,82 @@ package com.iluwatar.event.sourcing.app; import com.iluwatar.event.sourcing.journal.JsonFileJournal; import com.iluwatar.event.sourcing.processor.DomainEventProcessor; -import com.iluwatar.event.sourcing.service.AccountService; -import com.iluwatar.event.sourcing.service.MoneyTransactionService; +import com.iluwatar.event.sourcing.AccountService; +import com.iluwatar.event.sourcing.MoneyTransactionService; import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * Created by serdarh on 06.08.2017. + * Event Sourcing : Instead of storing just the current state of the data in a domain, use an + * append-only store to record the full series of actions taken on that data. The store acts as the + * system of record and can be used to materialize the domain objects. This can simplify tasks in + * complex domains, by avoiding the need to synchronize the data model and the business domain, + * while improving performance, scalability, and responsiveness. It can also provide consistency for + * transactional data, and maintain full audit trails and history that can enable compensating + * actions. + * + * This App class is an example usage of Event Sourcing pattern. As an example, two bank account is + * created, then some money deposit and transfer actions are taken so a new state of accounts is + * created. At that point, state is cleared in order to represent a system shot down. After the shot + * down, system state is recovered by re-creating the past events from event journal. Then state is + * printed so a user can view the last state is same with the state before system shot down. + * + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + public static final int ACCOUNT_OF_DAENERYS = 1; + public static final int ACCOUNT_OF_JON = 2; + /** * The entry point of application. * * @param args the input arguments */ public static void main(String[] args) { - System.out.println("Running the system first time............"); DomainEventProcessor domainEventProcessor = new DomainEventProcessor(); JsonFileJournal jsonFileJournal = new JsonFileJournal(); - jsonFileJournal.reset(); domainEventProcessor.setPrecessorJournal(jsonFileJournal); - - System.out.println("Creating th accounts............"); - AccountService accountService = new AccountService(domainEventProcessor); MoneyTransactionService moneyTransactionService = new MoneyTransactionService( domainEventProcessor); - accountService.createAccount(1, "Daenerys Targaryen"); - accountService.createAccount(2, "Jon Snow"); - System.out.println("Do some money operations............"); + LOGGER.info("Running the system first time............"); + jsonFileJournal.reset(); - moneyTransactionService.depositMoney(1, new BigDecimal("100000")); - moneyTransactionService.depositMoney(2, new BigDecimal("100")); + LOGGER.info("Creating th accounts............"); - moneyTransactionService.transferMoney(1, 2, new BigDecimal("10000")); - moneyTransactionService.withdrawalMoney(2, new BigDecimal("1000")); + accountService.createAccount(ACCOUNT_OF_DAENERYS, "Daenerys Targaryen"); + accountService.createAccount(ACCOUNT_OF_JON, "Jon Snow"); - System.out.println("...............State:............"); - System.out.println(AccountAggregate.getAccount(1)); - System.out.println(AccountAggregate.getAccount(2)); + LOGGER.info("Do some money operations............"); - System.out.println("At that point system goes down state in memory cleared............"); + moneyTransactionService.depositMoney(ACCOUNT_OF_DAENERYS, new BigDecimal("100000")); + moneyTransactionService.depositMoney(ACCOUNT_OF_JON, new BigDecimal("100")); + moneyTransactionService.transferMoney(ACCOUNT_OF_DAENERYS, ACCOUNT_OF_JON, new BigDecimal("10000")); + moneyTransactionService.withdrawalMoney(ACCOUNT_OF_JON, new BigDecimal("1000")); + + LOGGER.info("...............State:............"); + LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS).toString()); + LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_JON).toString()); + + LOGGER.info("At that point system had a shot down, state in memory is cleared............"); AccountAggregate.resetState(); - System.out.println("Recover the syste by the events in journal file............"); + LOGGER.info("Recover the system by the events in journal file............"); domainEventProcessor = new DomainEventProcessor(); jsonFileJournal = new JsonFileJournal(); domainEventProcessor.setPrecessorJournal(jsonFileJournal); domainEventProcessor.recover(); - System.out.println("...............State Recovered:............"); - System.out.println(AccountAggregate.getAccount(1)); - System.out.println(AccountAggregate.getAccount(2)); + LOGGER.info("...............Recovered State:............"); + LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS).toString()); + LOGGER.info(AccountAggregate.getAccount(ACCOUNT_OF_JON).toString()); } } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java index 9e1bc560e..b6aab7791 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Account.java @@ -33,7 +33,7 @@ import java.util.ArrayList; import java.util.List; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class Account { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java index 29cdc4d15..a0d921f5f 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java @@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.domain; import java.math.BigDecimal; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class Transaction { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java index 8356cd3e8..350104267 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java @@ -27,7 +27,7 @@ import com.iluwatar.event.sourcing.domain.Account; import com.iluwatar.event.sourcing.state.AccountAggregate; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class AccountCreateEvent extends DomainEvent { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java index 9d73639eb..3fb61bd08 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java @@ -28,7 +28,7 @@ import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class MoneyDepositEvent extends DomainEvent { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java index 995fb9326..bbba89988 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java @@ -28,7 +28,7 @@ import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class MoneyTransferEvent extends DomainEvent { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java index 64fddc16e..d8c295002 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java @@ -28,7 +28,7 @@ import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class MoneyWithdrawalEvent extends DomainEvent { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java index aa15f746f..baaf41f56 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java @@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.gateway; import com.iluwatar.event.sourcing.domain.Account; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class AccountCreateContractSender { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java index 932338c32..84bdff3b2 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java @@ -23,7 +23,7 @@ package com.iluwatar.event.sourcing.gateway; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class Gateways { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java index 3cfea0751..42ae7a1f5 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java @@ -25,7 +25,7 @@ package com.iluwatar.event.sourcing.gateway; import com.iluwatar.event.sourcing.domain.Transaction; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class TransactionLogger { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java index a5d82e5be..9379e7b5c 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java @@ -44,7 +44,7 @@ import java.util.ArrayList; import java.util.List; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class JsonFileJournal implements ProcessorJournal { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java index 81ec2e761..38e72995d 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java @@ -27,7 +27,7 @@ import com.iluwatar.event.sourcing.api.EventProcessor; import com.iluwatar.event.sourcing.api.ProcessorJournal; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class DomainEventProcessor implements EventProcessor { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java index a42826160..cfe0cfbb3 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java @@ -27,7 +27,7 @@ import java.util.HashMap; import java.util.Map; /** - * Created by serdarh on 06.08.2017. + * Created by Serdar Hamzaogullari on 06.08.2017. */ public class AccountAggregate { diff --git a/event-sourcing/src/main/test/java/com/iluwatar/event/sourcing/IntegrationTest.java b/event-sourcing/src/main/test/java/com/iluwatar/event/sourcing/IntegrationTest.java new file mode 100644 index 000000000..8fbed333d --- /dev/null +++ b/event-sourcing/src/main/test/java/com/iluwatar/event/sourcing/IntegrationTest.java @@ -0,0 +1,115 @@ +/** + * The MIT License + * Copyright (c) 2014 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.event.sourcing; + +import static com.iluwatar.event.sourcing.app.App.ACCOUNT_OF_DAENERYS; +import static com.iluwatar.event.sourcing.app.App.ACCOUNT_OF_JON; + +import com.iluwatar.event.sourcing.domain.Account; +import com.iluwatar.event.sourcing.journal.JsonFileJournal; +import com.iluwatar.event.sourcing.processor.DomainEventProcessor; +import com.iluwatar.event.sourcing.state.AccountAggregate; +import java.math.BigDecimal; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Intergartion Test for Event Sourcing state recovery + * + * Created by Serdar Hamzaogullari on 19.08.2017. + */ +public class IntegrationTest { + + /** + * The Domain event processor. + */ + DomainEventProcessor domainEventProcessor; + /** + * The Json file journal. + */ + JsonFileJournal jsonFileJournal; + /** + * The Account service. + */ + AccountService accountService; + /** + * The Money transaction service. + */ + MoneyTransactionService moneyTransactionService; + + /** + * Initialize. + */ + @Before + public void initialize() { + domainEventProcessor = new DomainEventProcessor(); + jsonFileJournal = new JsonFileJournal(); + domainEventProcessor.setPrecessorJournal(jsonFileJournal); + accountService = new AccountService(domainEventProcessor); + moneyTransactionService = new MoneyTransactionService( + domainEventProcessor); + } + + /** + * Test state recovery. + */ + @Test + public void testStateRecovery() { + jsonFileJournal.reset(); + + accountService.createAccount(ACCOUNT_OF_DAENERYS, "Daenerys Targaryen"); + accountService.createAccount(ACCOUNT_OF_JON, "Jon Snow"); + + moneyTransactionService.depositMoney(ACCOUNT_OF_DAENERYS, new BigDecimal("100000")); + moneyTransactionService.depositMoney(ACCOUNT_OF_JON, new BigDecimal("100")); + + moneyTransactionService + .transferMoney(ACCOUNT_OF_DAENERYS, ACCOUNT_OF_JON, new BigDecimal("10000")); + moneyTransactionService.withdrawalMoney(ACCOUNT_OF_JON, new BigDecimal("1000")); + + Account accountOfDaenerysBeforeShotDown = AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS); + Account accountOfJonBeforeShotDown = AccountAggregate.getAccount(ACCOUNT_OF_JON); + + AccountAggregate.resetState(); + + domainEventProcessor = new DomainEventProcessor(); + jsonFileJournal = new JsonFileJournal(); + domainEventProcessor.setPrecessorJournal(jsonFileJournal); + domainEventProcessor.recover(); + + Account accountOfDaenerysAfterShotDown = AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS); + Account accountOfJonAfterShotDown = AccountAggregate.getAccount(ACCOUNT_OF_JON); + + Assert.assertEquals(accountOfDaenerysBeforeShotDown.getMoney(), + accountOfDaenerysAfterShotDown.getMoney()); + Assert + .assertEquals(accountOfJonBeforeShotDown.getMoney(), accountOfJonAfterShotDown.getMoney()); + Assert.assertEquals(accountOfDaenerysBeforeShotDown.getTransactions().size(), + accountOfDaenerysAfterShotDown.getTransactions().size()); + Assert.assertEquals(accountOfJonBeforeShotDown.getTransactions().size(), + accountOfJonAfterShotDown.getTransactions().size()); + + } + +} \ No newline at end of file From a5ec376089b17ab35cbcc3dd63a411ee188a9f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 22 Aug 2017 09:11:18 +0300 Subject: [PATCH 344/492] Work on improved Bridge example --- bridge/etc/bridge.png | Bin 53487 -> 0 bytes bridge/etc/bridge.ucls | 157 ------------------ bridge/etc/bridge.urm.puml | 92 ---------- .../main/java/com/iluwatar/bridge/App.java | 42 ++--- .../iluwatar/bridge/BlindingMagicWeapon.java | 59 ------- ...gMagicWeaponImpl.java => Enchantment.java} | 11 +- ...{Excalibur.java => FlyingEnchantment.java} | 23 +-- .../{FlyingMagicWeapon.java => Hammer.java} | 31 ++-- .../java/com/iluwatar/bridge/MagicWeapon.java | 47 ------ .../com/iluwatar/bridge/MagicWeaponImpl.java | 38 ----- .../java/com/iluwatar/bridge/Mjollnir.java | 56 ------- ...ringer.java => SoulEatingEnchantment.java} | 23 +-- .../bridge/SoulEatingMagicWeaponImpl.java | 34 ---- ...{SoulEatingMagicWeapon.java => Sword.java} | 32 ++-- ...indingMagicWeaponImpl.java => Weapon.java} | 11 +- .../bridge/BlindingMagicWeaponTest.java | 16 +- .../bridge/FlyingMagicWeaponTest.java | 16 +- .../com/iluwatar/bridge/MagicWeaponTest.java | 36 ++-- .../bridge/SoulEatingMagicWeaponTest.java | 16 +- pom.xml | 1 + 20 files changed, 129 insertions(+), 612 deletions(-) delete mode 100644 bridge/etc/bridge.png delete mode 100644 bridge/etc/bridge.ucls delete mode 100644 bridge/etc/bridge.urm.puml delete mode 100644 bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java rename bridge/src/main/java/com/iluwatar/bridge/{FlyingMagicWeaponImpl.java => Enchantment.java} (90%) rename bridge/src/main/java/com/iluwatar/bridge/{Excalibur.java => FlyingEnchantment.java} (73%) rename bridge/src/main/java/com/iluwatar/bridge/{FlyingMagicWeapon.java => Hammer.java} (71%) delete mode 100644 bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java delete mode 100644 bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImpl.java delete mode 100644 bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java rename bridge/src/main/java/com/iluwatar/bridge/{Stormbringer.java => SoulEatingEnchantment.java} (76%) delete mode 100644 bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImpl.java rename bridge/src/main/java/com/iluwatar/bridge/{SoulEatingMagicWeapon.java => Sword.java} (71%) rename bridge/src/main/java/com/iluwatar/bridge/{BlindingMagicWeaponImpl.java => Weapon.java} (89%) diff --git a/bridge/etc/bridge.png b/bridge/etc/bridge.png deleted file mode 100644 index 00d3e611c1f72e1b3411c3c5b327f81a49f3a78e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53487 zcmcG$byQVd7dLto0|Z4uDQPKbIFukDNOyO~AtaQP7U}Ldba$sTDj;#_k`f6i3F$m= z_c=U@&wJnZ8{ZgrT>k?0-fPV@=WovWn{%yYfSioz-8%$#Kp@avaWNqU5a@;w2!v9L zdL8&nw#Y4M5NM!ATu4CaZPI#^cJTC=(*?h2cu!ihSkUwhxuA@%iQH2;y;kzASP5hJ zJj@l$3c_6+2b1y|qxN%;SZiW>gBlA6yGo*zwT&phM0H9Brrv27=y+rBRIKP4)<|UO z*sqXX%t&+1H01|ra>I|c`!0UL33tL@_Jx1;TU_>HqG0rUX#;Ucacf@w@vMmj5DEl( zfwDU4hJySNH2e;F4e`@Ek@v_S;$zy|XE(34YRT!={wnml{M(}#y^t^C_XTakPwmm0 zo!Q+tu7MU`6wVnX-L!}pX#P}}Z%FHylTKraZf9(WT_ zz%T^0aUi!qr1t_)1@B@(ZlyD#gHb^D{e*6$-$DZq3vXENxfEvZ^y4#sE%_ywr=$-7 zf#$>gNk>TaA@zAfyd9?1xXG_gzG9wXKtvi5bG;E0TEp!vp{ZpCGejaQFJQQE}u;NCBKze*gW%*CDcc5O5?e_-!t9TMV6%r*5+Jw zT#5BPS%Vq;f;7vQQQlAi)E|+pcIn*yo{#(?stMYKk*zC27+r-`W8MM97zZe>xaFK$ zJI$ZWGx?{>i4E6b#*iXvakl8-VTYV#vSs&ZT0p5ZaW`_%M+GqG71nu81``)QIK?;BDN7W5AK9wS5fXBtXuv{OLrAkVEX{=F z#36?$A$;mSt@>eVE?oXX&%=dHjUe>7WR$biI_**%_gC<$U_?=<*sS=nCHp5Bske=| zUcDSqTPv$@RS)5cK5L}6#;6js<=-GgL}E19NWLrjoJ8Pq%KPcJ#P#gReM#9k^&vum5;@ohnFJKf z+Ija3NCodAO(bAy^$FIA9V4~7DQX*YX+l(XF@%se((BN`PZX3`lgmg(NiSjYz&!kh z2(jv}Jupb#yIcJZ_zm*-Xjg@KS+!~UPT+n5!pIHA&n%mWrzFxd$81ap*{|G2-;zcHLmTA3<<%TPfCAa|q!Z>J+s zRe9iOz5Pq++1~AP)sxQ`Tc@cmPA_lXFBYI!sCB!id*h;q3ygu^xWUr~}C9zUR}-%e^K&kqw_avAyaiQyxhB$%Q7h7gR4E#u=&+%_ESjQac& z=KWuV#SUxzclw?OYk6}HxG_&N!-Dz3`NpA!rIJAmyp=LVhth{*vyY#-G{&2W1bkOM z3{GC<#L=2zts`~kkc^6g^I8Nr$K!j;5u-`r7GxH)ye?Q$-epQXbY#=Oa1;R|7MS6W zMr@YH+zzc~4@1T;)u${!Cd?uj}WHe)Et^>Gl`1(MJcz@VJzB3wmJ`JCXU5ig4#(aFQp^#L-0k82L}Y zRm{~foGt=fa9Z9jk3FKcJ3Csoo<8^ChbQ-61Vm20y;#yF;c_}8%H`iV@5Q|RWtkOh z*sJkDH@u1~O;w*g_3_WI0g2E7;SbBIxRX<2W+VQ^ZzCL*+IkcF+M4P?1czw7%5r><4lMHF0O&|l5fBF%NAFY&Frsq z-ESxS`)lq;Q6%tvpODhVC85ZRru`n-dnEOaE*o`9aZQ8np76nruCm%#x!zR3D!INQ588kmq)WBjV^J0ZOj9PKb2X zuO~0Nm1fi@70n{Dg&ib-SiKQMmN@&&_H=oxahHxn(`Bxd?;<%$R>xfgURc9_Fg=HP zwjnx_Ir*`!S1Q^}im=hS_rMtQ^+q`5Js~t@*Vs_LVft1Vi4JI`U!re1>)TERMV500 zj`-Jxl^C3sPJ}D^kmrw{s;<%459~(Meu3pRR8(6^Q3ocGzvOiS(tQ>CEt%0qZu@?z z!2=}?BeRHPh3lD$bcX&m^joK&k`Jx;-~M{#hso!t2FNo?Jlv&4X8?I`9o|&Vdg`dw ze^-Hk{gZ|CsV~*tcP9|DA0w=NNlR_>Z-zdYcBj0dj~cNlh<=P-!lz9Z-bEtqHToGA zj2=hVgmd~h^@vs`J=j`OX0_`5 zMlyZL{P_oeX!*!yF#PVlrNj;yu?R)@+QVlIc`1zu>ky%!bCgoWPx~e$i{L)(wctl# zsHo~BK%^?7m)*lv8)dO9P|A?;yiHhTL9gx{{y)pG&$@UT=!TYSPTj)-le&nqDC6!n zhDg!am^*RO*d$~lM|ZXi^ZdbCI!38s6w$dda)QU&Ac)OpTq|X9q8{K8QOL6^MSd@< zzz>R#%c#2cG}cGck6shqxDNusSk0U<=zScEt*{tPo?D4bh}uD((pU@?G-RHG0eJ5R zrbjLnI%;&bZF?~!rLLK?l7v6=Ymp87@L6`}suUvmi;f%UeHIF$XZ=kZoa3Qy=4`Uj zRvAu|6QSat>jRa|b3303%h*aHk}fa@D!ay?w7-z2S2slJ7aC?&fl*rVsGCi~<`Fx1 zwVJ2+M=&)MKQKv#7&2Bzo@@5cT%>{_u?VV#q!UN93MG4!RZ*SjqZHL?Setv3$>l%j zpV~-73`dSe#R0;Vy0F|&Uy}HTn*eM(-6oE1KboEthc`iiW*G03EuSj?X6ZO(bzYu) zbrg9nU^jInboaRNQ68A*{X;?&fpAdB`$HlZTUbWE9vL?$@ciYlk&9j;qpn819UOgV z(sVQ-;swjLS*Nzsu<6lUX&n9pv(tR|Ot_BnUt|bc=$(k)zzog?NW7E$;=>6fHc0BYL z$=JSTxjntkl-{g0Xg=beX;P(hsHUsVc--4-3`xo_n>4qV7oO0Yx!L4x##PBVE%v-V zw;1mMjoJv$59W=M;PJvBScu`Q!s(EG5O$ZGHN z_wTpwY$XM#pe;O3-ZrIR5W1mzh9!7IpRDxn^${S~CyiVmNBb=wZr#}EzA3Yp-VVW2 z%8y-1W>SWXaINNp*7-QuzsHA}+k6r$@_RO;@@S)R^c%hr?*EX3Lbxt>)Y#h})_K3g zb%w+WBT~g^9p86l3b#0#sMmHEGIpG)wh%VSSRh>}8Tv|^<7bv^;bRL7hT%2S^>|X4 zR73Rf;Ro;GC7c+kDe6lyor~35!qzbM1nJf}@^xLBCf-o9{7VdGTtf4ERmMaNWE^1a z0Q;A-x+&mg%3RD0t_BFU604=}KNLI0A2M!^d<9t`>;qIEcpCiA(;oql@$TPo0QmOu zY3M&sk@Vc347FD}9;yLU7PL?f(Mvm!kC6T;EToDvBA>=cB|iD94#=Ida#6(uExkXf z_tE8r!Okwf7C}1deZWnB*9wYZDbV`Mhc6LBrzt;56Ij`(5L}56B|}!*VpVxYv?5K6 zQ2c*aCZwJjk@-TG9^xLa) z0qE}g>mXEn^-HSdtj!8;yR0{mq1A{JTqSY+1%{_(Dx$g;$a}WNJ_QS&t+hS0wm3Vt zcHhQy|HXfyahez)w=j}v0)X~k$~rde^i<{FoQN;>@DQ*ZIfsysaQ&h0_cWA|I?2s| zh`5-;x2OesuV4@81X-;mbiud^g}>kjQx%i*wi67W`xx|36012ZJyTv&6j=-Q+A!@m zRn|`9pBCrUW1M`<`0TK?LAx5F1%K{ZKPgscdF7FXw8$clP0>qCV~5jF!IXbap=E1n zb517a^dPRgDZJut(|L!^uS|)Y+g{2HsSYaLW0f0qVs-wc!b>wHO2$z9t?FRHlE*0&gbi8bIHomh7z@pxhAI>>ActRc2=^%Thom{4@yh& zL*Cfrt!WMa98Euz9(3ou^;v@PVbXx@1JAf$hc{-soy?eAM;oV<3!j4*oLf3`ebxrS zUiZ6^0DH&|#@0|ywx}>2A~g5qf1YfKx;I-JeV7!MISRn0)1U0n^(XkSh3jZjQD zqL!*ttu)&;(Q5E^q_ly0@^UpWU=}h$v$NpaS>fCr}NlO0D7KXn3#*JV_ z?I4q(ga`XpPtUB@9&0cbCQn=x6(4>l%x_^kRGQ2V;RtGLh%mVIwwBJlc4k)y_fE}> zZ^{U|`s~FX>N}tzlP!VB>-a3M6I4bA&DV6lRH-zTSz444^f#KJCVjmhKeOKbWpK?w zoor9Rppz$MCH3t_TNfR*TZl{n$*9aiSrAzF#i5_N6yPMO>&n#^z+6pe zS_$cAyU{lU*nwp>%&-}O?9NO+F4v>YWq!AV>S5|;M=i@d5(bjl#Xau$*D+_xwI*v5 z+OC^yheo;CV~pR4nT4(OjUto#ORQn|in1gaD%HF-*R&5@{112P`XzocB+bBnS;g&G zEeC?O(eX)y*li&Su;6h;LS|t!u>}S(gVXB7y`cEh`mSB;+7`QN#70aBU9a6$;RRL^8ySN zFL*$mdF*)PPGKj)NZM@I+Zc`Rvadc!tI~%+2$q|fge$p!T8pPs%TRNMI+okzWahPp z%9c5$>ZwC=j0HvM@>aUBe{Sdlex_gL6a*C7z6kQ6^?bxE8iIlpC2Jx1#IM&c1# z$B>WJL;m7Woywl!;rnWh6ER_#-C>zk=aQ8*&6?cYUCI|s8rPz zBpsqI#WJpnGgNMJ7^L>PPyx)UGgAi@^-`z`KnhvM#NP?FKL{P<>SlFQX z;YT*PpT_P)VvBtLN-YRX=$d+b<1rk~A@4t@`UHVIFQ?BhlxOpp77MB#WS1AgyNBvf zs6(Zwk1j8>#6OrviZ3g&kzeLuBVj_dqssTu*X_Nq3q(Wytcu&2f*h4y6eyhUvQW6l zIr1HYdk+*;WNY98vZ*oLpF@su19@L1?w1z2IU9~9eu7oWNB2Ec?yCA$+mxTGXNGGo zvpu}FqJtrn_Yq*LOAlWTX`JMY)HFNP{OA{&q?G7SpAooUc#k}+Yet2QTFS_$Oc=MW~e8FUElxEH7ykfoG6p7xFDZS`bXn*l`c+#_A4i6 z7l1Mvx80wbUl{A3eB550E^J|ow)FLA`K#VSh9vdlS0=i{E#KwEe1%QBFRPly&(b!jkm<3*4A#6RYv{FKx?Fp1?|9V>9x~9I(ol{P zcPQr=$%3Z;=GcH(&x68pOBae16QJeAgBGri#pS0{a#8)+e~r`_6ejCW<|z?O7O*R80=Z6|#;$CXfIrqE;}nGY;O3Pu z+`|P4M=rW)cSp@3rViN?)wcj=z;{v#ZT~{Ow<%*PK%>99*k=8m%ORi$etuS)g(Q=mSt=r086^hmZ~A zzN&(p$B{r%i9*<7;pk_^L^Wd9XToV@vHicbBFeE)6lv& zvjXTbe+N!jiXOy*NyQ_2zjW8bU;FNZ>I7(&?$4*}`SfPbA2@oT2QB>=+cFx&<@w;UGx zV$~RFpESJly({FCQ&!Aa{8mu$nOowICd*A9g0xSNoR7xhl??`g=TE!OGqLDapa%vh zL6Ikp5fVAzbAw;CEzc39hGC9Sn;eR!GTp=8lIu((2xEXd!UM%yiKDE> zkSxm{tUQFR@M1Xi*ez{9(<4`dTkuTHkrftV`||gG(IYT;K_rfnJq2%Cr|}b{V>)IU z(xEY6`w5TsR0)R`8Ve8d1a{YeP8xET^mji-9}Kp#QXeY6F!cV$6hU8-9n$X*6uv|Q zN_$rOJwQaD|0t+B5r67&9=`;l(i}q)!r$Rvxjnq=<@9jwU_JkmnvQF|OI~3ssbCCK zg1EZEGi%ZqsX=6G>o&0AijcE_+E=Oue{}SD8!T;7$rGARzZwiwi+kwyO8*p@$k)0< z$+8*vh=;SR9bZA0;gAVsE$ymlQCxuBaZ}X5=&C+?%iL{G$My&R8?9q=qTb zQro#N!dRG(-|mJqHIzJ$6V#zn=iO4SMb?3x(7oa5*hN(sOmsgW+(G410Dw?7(r-&??e7+ zZBURSrCC#VZS+_3C#)9fWkoK81NpH9#)uH0hGro0;Ny@uK4M%;CNxVeC$DQ@vCFx3 zSatk)GW_(T$ZKL8a?uU>&p@EbyKGIWC}TZ9c7iJD`K(-Tds#b{JnGV}oD=mmwQp9d zdty7ouS+i!NhViI^2TSn*)fSJi~fhC=%~(rD)I|A83G zeZi)l7BSb_5!IGh21=w&-!FG zBLvchNQ+!rR6{wy6KRnfP-xZCBS5c~^7_c?v;HZFUN9OqtgBJ7T{{8kwAzQ0QTf-3jc<#5G4Y-(F~r0;z|JNo&ne}0ud&EBMRBr z0@4hk0PRCI1rWsb_ZENt>uaDtuHyA~3XldU5a79&9`+mRYhh#)bdk$yY)RQ&@``LB z(0o}0J})6=j=(3-qZ1D!i?X~W8I{=~)`;{oRwVg2F(d^--49@+Ae!jqny#zsP;DYG ziWkK5aryF1nAFEdT~Tpm?hWb*gzOSm?S2(y4P{{A0Ks0A zkHRGhJM@8+v~#`@-Z}CgBZQaGONSCr<|88w8gdW9R5@Gu(QjfF>-_q zP*QIg87jL7G8E!Ne7TVTt|EPquKdUzQ7NGVCr6~^k?4kD{FhJ}2nE8n0p!2o_X7xI zEDi;GUAoS1%78fal4B+TR*ZcJ_Tr{N_{;A{0A-U8KirG-Qj{te;u0K=$3M;h!f-Zn zyGuIE6V)C#iZg7%LSg^4aYHN?Ra9G*2XVIQ0j)M7rNlGbn)I!K^rKYuh*6n(2-8R- ziz;Z@(c8_}AF<|8L#AFKeXR=tTTvfK&bvLM_Xn!p3P6CCZaMm((l(kOzUaQ4EN`Mg zCsNjUL(==nVqP`SHB>4=gc}ycLi3vtU*HSCJGf&ik3KX7QI(VHTC~_>N_uA=TxEEv z*@CrBY0_JT0z?lh1vBedg1fU#btu2FN}SROs$U|xy!}fhT|))1(5u~^FH*$?R+A4F zZwN@{&cJR!MWdsoRIO4DR7cE^c+UDdzcA^@Zzb75{~$D+=}&|OBr7oEIQzKi0FGJ# zm)8Ujod?S00Qj&0=#59jXw8^x51@d$D^CGe7bHMBYVjw$zE^6Bm;u^S1avC}R8mS{ z+dvPD>IxCW6m;^C4x+>dtis3gyFt>Firx~)oCq;jmfnNmX;VTW9hZxO0*k8H%|inQ zh=Dj*1^{IjIU$)SP;LlCc|r8F3>8Pb)wqq|V8yP7>G%k!he9=!_n(2SAmMx_RQiyd zB=ABYuux@Sp)rf{0SXXd=FN+TcIn2l5wzYPrM`>tZsAUmA+;d-LtFNV z1xhMLCi@UTj$TFtcE!Npf4&#j0m6AT5Y7V`4i-DP$?5D>3LV}-%qmPOLM@4X5t1_? zvxAh-Kj4gN1==^7i1v-ny0|Dwh4CgV6@TZD)taeqqbTp{(weR2RGCz-y-P9{&s?Pmc%v(Ww$w@M zUGjnsveuns9Tne;mD;9Y*C+LsgBD62Es5L098%#}%= zthJuamW*3#e(=s}kOSZ?wDLxt1J{q(eGBTG_tyX^$_>9*&D1Lcg4o?dc#-ly&(}UU z?dI$-cX!e7D^yxY_{F?U*|J(2Ue~y>Z@mE^UHYX=1 zBUVDl43@)bXlUr^>G}EdC#UtdqEj7EtKWT0(3|LNb>N?tR@=}E^j28w`gFbh&#&c% zw6v^)BrgcO--6028yX7fdp%KZi)6~r9A0PUjmM9Vkc?y8n5qp6I0vzkwV}MgL9A+c z>oBG^9~e338W=^H_ln0OeVH5^=ARTY(Q?x!0Fsqlb-LMu)B8R_Y@ zKD8h#eW$?dHByB@!Wdlt8R5J5?ZP*6w(?{3~na1rZ z;A>MHgg}v+wO08pC*4DY{O*L3Cy|va+)3 z>g;vtnOcG|+*q#ZouIHGEE^5m|2d9H#GO^) zeQ7%o80C#fX2c!2ZWuEwPTI};^Via_92^}1J;uhxDSwkYY>eRk ztB}XLF@#Ka5P-af+hOxUTMyFuS@TH{U@itPK#&+PK?v|QFa|Kv&t}{e!g&0*ryI4W za6SM-8fbuWm)iRJ`sU{|x~WTaTXcX){90jl_}0(pA2~5<*DC=Fd_f7wqF3_v32!Lj zGaJC#fK9otL2@d!nw*s<;tjuq0=7?UM+kfi&>}P!qU=`fu0_)MUv;b91*bl^=9tV%|~kSE0_Zh07J-8BMo6a%V%tXcjvnDJLu}Y z@lxHb!&AR|L>WD}X*`ID+yOZ2>K@Wd13;o6ud%xa?w$(h z9xw`Mm4-U=4A$KpxWfTV!G;Nw>iLE9%@{%idW%>9J|aXhGSW)g!cX=Ag(lp9oT zi9+%FhX%~i1AqMZ@r?rT-k;6V@xiRjYf%|HtRN#V=(Tqpw!2Hx{X>AG>6>x)O-^b! zBo_j~VgD5FG;>eNOVtUQ&3ug%GaesgipFU*t){CBIA|K=RowO+ClkWgD+B51xQwt3 z_cWSr%N>SW@6Plfpfu%6OIXe}yIq=M#Oq{lc+GLP(P@`=%L#MFkrfcQ@*x%I;dS7w zJ%iAXic7PoCET-_Za*2As5A*9e8xIE<*5a@s=L0vXLk=s4v4s*s@RzsZDTXQPnZcp z)|zqSNxHi?r)v981^^A&muJl>>p-4Lf#QMC4XPrv#u9FsRsEI&*!r2ieHpEpj+$ED zf&*!cVy+AWBjY^tH9d3S#Qp#p;1gLkIWaMh)}GjV?k@M278kcW5c4<$bGO*Y-4bz< zjQw=u9sWlc=!M_ci3$1RC<)tPD*u-}a>v`2wKF(9k+Zughs>2)*S{&mE9u;Nr_c(# zy3FNqeg;I8vGH+nOHC<@kNB~158j`Uj?{)RvVv&P0TJz@i;Edzl!$4A9y?qm#GIE?+21(+!s9k`uPAJp9h_(C>)@Akr%a<+{pTCaV77%zG4&;p9lZW2;0|+$4P`=(GDc+AD{rCpIkqh!_Zn2;$0%e&y!o z1{jKVyZBTmjj-{iNwk2m6SQDrW=7e%VjL%}Sppp$J;i?8nNR%=HmCpvaXBJ=r|gMn zXx?7X@uQ9Jt)3{UCnLFPIynl_)<7y6p}Ud7?{WUkWlQ6yR>Hgc z9UL4Gc0-F%zUVGJyHj0BYiw*xc`SWAGYg+7E-u#Cyba>M39PxbZ*#Mxdk6@0QLnmG zyXWVv4?#j1?#~QcO1jI7N=vCdLiRrbmoY{?fx94`^J}Apx3!iyRt2+z7q;2GZ*;?d z1pAM+gg%J90RrVA@X%_cG*r{r*jQ0f(a@l|U(E~_E3yM45?yf2!(v>KZyo?kQqr25);Vh@RPGW%$5Y zfDr}3mCem5NwZt{cs~vf>++%?~k zhP>eJQut&kd?FPN-2vm_f%1qDtCXU7oCyn-SdA`!YV7s`CS^uVSbUIyy@_$^nfehX zMYrGMG-X)}Un@Odqvk&r$G`xIA%v5=-aQ0p)g_i{1JBqVU?fxrb5(sXE=B|9?(!C+ zuyWoN%KjF%X}T@JZu))BgPkqwW`k@%_2zzgH$ZX(Ky>&;-+R2f92G{JT3JzH0|3K< zf0!J+@HHT1nPg{uoY!|aKjSVYcwO}SdxI}+C02Glf3C8eGuO2F3>|Q40U8azC65M5 zGXfGCgc>#5s%LwQ#<*nunCQ1zry2(!+S$Q^z@o) zD?nT;6dxUqS;^HbhE$ z4W#71tV#U#`?XR{s+!p~69Q{U2hfy{SMK~2z!>^$0{_4(mpW{)Kh`!L3a8Ks3*_0e zc*r+cujt{Q0)WTqrP6g!UQ!gbtnUmfnVEaeT}X#&=tKTZy6KJAIn5qrExZKucSTdO z#d)b59u3>yaG}zsi5z{f$^%8%j82FW^v)d3q=$l};slBV#h0BJg^~BnVNmP_2QJ}= zp!D9WQ~U*IftY{HZ#M#C)I%u2uqy_mTl0|FHYr!quQteR+; zK&YM;U_naI7KTWyUg?NEOAYvvl{{T<3h5T#Q3d~u2LMWXHvQ=xb zz~!?95ZVYw@Lv>LfIk>RfY^yi$W_+ZxGvqu_1$LuE6e^s%UMrLI21ZaWR~5W3Qe?qgDKk zxEDA;i`BZ(X+LU~>txPk{QQ?Bonva9tYu-`uR7rF3OMuJURMsz8PE+hi7rJA7xsd| zfGZ}-#7mw0ygNtjhAATlTr08ZwmEKp%@+s-_MZ<^js}+KbdL@ancyoXnd285U)E-E zOZfO@z~DZGnDTa(QfQCLrj#Rfre_1i5)B;Bx~b>&AZ)w3X-;8X=8Sieh34sR43h?l z#6vm1HJ>!ZanehO!gxz1t|Lc=(O3MlRR*J{feUk&OwQ&5f-ah==3!{ANx3^{m_X;_% za-f42%6bqiZO%^MlGmj_A!XsI-E43?ZMJSa4_ou~I0#BDbz5M1o=<|Csw02l4%`I! zWO?{B#af++TZH@xe%P1 zbW*wP)hQ5CWw{}EVm53={~_v^{O1Q|xkC*ppIk!w@>>*uw#6T-dPA?Sd*qrdec|_5 zIAA(k-EuvbjUMSZ<=i@H?P}QKf=3)$yK|+C9de3TmHNkxo#Gf|J-hpv+0=nN!8+=# z*p`wwan6=wZIc!B{53Tzb3Ks+&&!C%yVMt7iFe>qI~HImd|=iWab&+$*jIddzA_?8 z-11gp=9kCxSwCEM#^p=?qipNuH{01Ws`u_*EWOn98(|q#yv|dOn*bfq`v7gCj2VCK z%h}GqLXB3>BW25a4-*_5GUl?de#ql5qG2s%Cn-=GYW-{voHebcCwZnr)D-y6slVgp z92e)7;ECjY#((Kw)@^s2N2YX|({&}T_FQ&m7t>=Wv!%IgJ7zp7G~qukYlMaE*mIt$ zil6B)f1_6kvdF@O?Noa7Hwi_VHyYZZEb#HV$5S1qw{n?5p5T?^REpnfhL+E$W!y?| zbYHdzNDLrm-SkMxB}l{rEaeHZW)_FZNEXD16B`&AONl>aE=Y?*| z*_Mg>5vE@XPZ6>57w<2k$Mv(Al`LX*F*kV0PM+g%E`%M1ufVA_9#vF@Mt8z2Rw#R( zgTZ)0pTAMrwNqHr&%GqKj^c`exERC?Cn$;C{T)>h_!TkR1=el z#dfEwr$5hQ^x#Vh&zWZn+}~M=N3CZ(bCq1@gxEe9uZhst;}?$<42}BaWs1o_t=nhp zJ$F-WMgb;?kzuUf9ZtrF39$j3kXW37h5!Q&aSxhb&(w*fl77dSck~Gckmvln%}moy zTL)gZTO5wQ+xm^Rm}_pZBnLyA{f6iF1NP0L)}>7hoH}WYW4T}o^Ym+=0BNo5ha{2^ zsbKLs=l+A}#eC-+qCjQq;hr2c#0^wr@IywFuSC`dgSMDNZ`TG$E@r4lT0Hok7lbiB z{&`%VZSsWgke3Z~&c!BKx0pT0Jm-;N-dR%*J8>_zveARgYm?UyCjvJ%N{Q=p{ZR{=ffbHwojCG_T+P_$kCjHc>NE0McuGik589yHPR{3=j-6 zM1C>?j-X&me1MiCZs#&vUk367=yt5;V4Mfqq4&9f@v-FR^p*o-j}O=-UaJ;AO(YLs zD|~IUW6!-RsXvr(n*iZvc6EVxsniO(lh=^j!oBi1sDldvDNAsUp9@7E=8wmBGwI+N zX1-b!TQ|(Knfw=4_pKuwN;}+?WIT)0*tA^hL^C%=@Iq1gs`e*Mso@4syZ+0irXSf%|!Rs_D?wHvLI${8CP?*6CGUmg&{$n!|f+(pM=*niU*7ru}9bhXG*W-}K^|rV%UUdM*M10?4#6i9| zLA@gBg$kow*VR6t=AI6V&XMzEJ~pme$7 zGXLk_Zh~IWKLoD0n*l{L0B~Roapf?872Zb>;1@WE3gJpm|Nc!F20L=&alGj0*t%H4 zz4(6nVz;!~q&{!|%4s{TA@>?j-t>1^z)#W5GY_P2t97o16YdQ@7&(d397V#Vm6;~Rv*{b(1T!=(VHiqlSfdNGMeThZ84MGuvxciT8BqP zx-AX=qyZQk4AvzYcLM*WmqnBxxqdz*Wo9MV&9Qg#*hOQE53k5P;IyyII&0rHqJmC< z@mnuvIz4!yDK_E<-k%^8WC7m&*U|F|(7VL2drkN5@OBaR#V*NoCi3Dwc#G!IKlIvK zN4&AH>6fzOfiz7&?87&v9kcW+L$ktQyt5}TIMcmmpbGDAau)$k;8ri29p{~Jb_>ny zamVKRde5Mq571Ye7_RJ_t;nL0Z1~(g=*wg9m};5sD76$$ZjIe zh))cctfWXZRM{GF1=5Snh9uYjTscboo5{f_Ahpvzs`-| zJ(X!a*`s;FY0YW{sXwG@bB2hBYhqc+Hp(pyBb15{u>N=SLok?2>a(NoK|e)x-C?7d zYr6ZHlVw<|rS5TbdqvOi5KVeNriWYIz|rN5}hd zlHas4q>v;)}~(5&-)fe0|dcOfDqoY`?VU#St7_J7)1Pn7HP$xyJ!xxzgV z!za*Vb%Vp=&6SAx4VR^OzIkIY8WnMxBNUA+TRSs0^&zO)e@e8@>wgz)of&EW)JQsT zD5H7P)zE?Q(Cy`t=Y_D~lW{k5co(DjU(xms6u(r{w-29<QyOg?`%FL#58ICX zeKe&g^WWn-J|E=Yo(zaml{q0uRsv$jlD<1;muVR{VLe1d9erH*sEIOkYVelbO*qAv zD9UXtTc(3!24`!j*R;iz?R3PaS$e?+;*o#Nyg8f4IEDOEGz$)lD$S&0TU)p%EOPd&hmm>a$JyNtAsw z!@A>?yC+)d>>om|D9Om3)5D=Ba@FpN>$cU>bCrY820KRF2x`4{FH9TCAFDk? zb=pJ=TuW5>;Cuc1rjX|Gi20)%EyJHVDdxD!_0**f)xUi_$&dBT3~6>Wva5Mjt`pt5 zcmvMyvF}$PpT0>bhXjMG9rH+kn9-GT$$Me{uX|YTS)7TK(<&XLRV10C?jBv$IPP1b zTs-ZSEORxrb9flD7F>)p+^h-IhD2C74!5-FK60@wD}B`V$z^9;@6&t=yOOPTG>a7^^J-GnELU`o9;f;D|zt_5z{rqEVt zPG$~%VC@wkdvnFd5P8{c>AM$G35nY=i)vVb$7q;&F7K8dp`fW*V@c$OCr`K(G?ur2 zNJyK;{3Xe=rOgqSw}fGHMEHpV2C1`Hbq}{Nmh#_|3^R^oMnnIyC=h}^9K68+s0nN7Ln@XwJ%33R(?`?xAs=g zCE@ODmK|FssJ9aF9mv@@CRdnjWrB=b)y_DQ;F50er1YCMIomgk(J}(BPx{apQ>p!T zS0q{Z;FD$%&vBQkKm+H)O}7J&w?-CIrOX^^qqNuXb~V`+9{wz6;T5-2ZN{z8^;dvY zT=`Xm%OLDn9Lx|aVO%{+jQB5gesh2Cczj!9sndEEDXZ0lzyAzPBTnEsd6l(+89Sb} zq;~siFtTXFxYY*cq$zD^|wZsq=7vR5xlK(IQfz}F;RTErE6EOulGK4+veUk+( zUzZ~N@mg@<0ij%1LBfg8K;vJp{g-@bn+2W8pg~!19FH%w)Hrz!QGB#4t!V zbx}vj{)9#ZliM3*B55o;AKJ9_?8_$^?fa^K5*_(^3gMTP59&h)&0AU)x$m?LKXHvU zBy)W=_Z4elwIef>Xs0F_U3k~1=;f!Xr49UeyfT9s1p|1OkE|6JOoMG(5MZ#pz^c zNimLdwBx+;m3i))cs?HfX^xzAKSdR-T4pVK*LKrt{%Jg+mvz@0BG*v{iNy9yxqf!o zF}VO4KgBW7IUI)Go;&uH$$Ra=RnGb!?kmsl%hM#32;U+}!%rO4%byL)={@2l{-_5w zbd4L9#NLadAhtJIcA0{VE~&)@m3!ou&MNE()=UjB{%d##v!&k**y1+Vuu@~B@k`4C zj|z%bwNwu*4gbZ-IKF1#fMi;Eeb@?g5VA$#Vj(4~a3q*VeC0fgI&6w*^fBFQ&6G-i zX+OaNf`#}ai4t%I?zcx1SVBIHKFfbLCUNyW+Y~HK1<@3`q_zL1vH$nKW!wT+s(vzv zcE1U>r?n=N>7mSEXF;*Vq~|fIpE9MClijpQayF|zy7p;yij^+`>&lf_sKJ>gU6e+! z?${%fvQp*+Era}7P7(!~%oZi9ijwEbvYJK1b5!C$ zp}U2lQ@V%q4C?E<-@W%a=YPH(zxd;snLAfp_gdGzo{ujagzBgI)ID0Q?>7}k+QZA< z5-_l-Z6#;U&5&Y&fIUu?ygKf+vw;8o{OEtG7Z|tI%E$mke6Z z-N)Q6GT$`QT=wDCHh!kQ`Pfku`ym@Ds$N z;rqVRlqCnSx1Qsor{{^y$wNm});KNB5J@n2AIS7Cy#MdV;kajzZ;8ZTooM5%*6{_* zAar^?L6-K6d+@R%ldWs7VNidc04|GMO9k2A*OGs3K_a&yL8^Kx|8?K?_(g8E{?7g83x-dTTOdW$r0 zI5v-_Wm7WvM%JAlO7GKM(5cnK$Xr!L82`8M7x)miaWjy!wM|tq(dsM-+*%y>_|tqW zcu>k>I5olU(5wD|E&m#Z``5oJrVk6q--!<~8&1#S0JSy&R|qPFmX(!NTLPsl zbCFyZka<>HJ1ywlA(FB5juW8ZfQ(oH4i(4<4D|7iK=}W+$Dg3JI`slmV8k|-=;I_( zV2XXZ0N)GrlKH(aaVYAdQ{0^dsP$BY)K*vYS|JFyJp-8Yt4}dxWOAswgQ}Aq8?E&4 zdfwkm1lA0OWW|7nybbZBqf-2^ZfY=UrS`7vr>(>W45uJK zmjfsvk;faC)>E(>nLz44=Kah{Ou>jH+XadNQ zgRba!pww>UV>QhG&11C|fT#%26Yn8DB@mZs@u{`RTmu+?S3M{KEDuX_b8mq)i0Gzr z=!o@eU_UUBBQUxLkT}LFEVahC@Z*Wg#E_plngXA)U42U8yew@5S&0Eemg4t=Aj6*z z9$!6psI&a<57@wVU4S0kyV3^yLR(QNakT+3pTZ5twjuk|oBmiKbNs<7rZUCGewSXX^L zz|sEQnN$m;wFsZDS72eh&;>L5wFn70WGuAdW=n_!cK~}^gmv1n>?U*O8PFLkp$ z@YZ{b%}J0FLUlFWOgwNTr=RKk_a|r9>H^0|o;dN*{4Ce{dJ3i@7eSQ5DLV;u@JT#F z3T27VF$!qqiM$I0Mz25jg0L-d1M{qLFtV)~CY`JUIgEVEN59oq(%zurxQ5dY>=KLR z&t4E*U~8>83t#ZTh3Ca)KL99p8D-X3i$2E{P$EmQ;**BgMREZ>l>O}CdM;EXrioa5 ziTGYOQxIxAnN9ZhGd1640>1nbBl1-VJ{TF z!8ml(Pn*oUZ__PHGzF0gCx+sf*7fR?b%s7>PCgE9>e7@smUQe=s%J8A_y9rBoiUbx#v9v?@iARahmJZ*(V@((cnzzN8lOEv~OM^1^y@bY9N*%m{0Fg>@3 zZ4&kQcNw)j^a>O4TeXlbmizXVST@68G|5^X-@WU3Jq}D~(glt?GVAMiVGNdTE?1!< z$a2u6$d{p~Hl_l@Tgv8C(%|&*Tp)*BZDI1d!x3+L8A+u4se7?;&??*YI+u#=v)1*? zPvocL%EmdVj8IA)8v?Sfu>e^aCBha`@S5vCms$ED|g+q!#T z$0Qc&Xz&6)@-YeFU4C%x&f-TpBtALvME@{s%{kL2D`NTpQb_*ddC zquPBJ@%=r(EdDYKQZQJ}Wiwx(R*mg?z#w=Jo>FgpMu^yVWv>}Q1VW8Qd)cP zNu-Av&WSs<6X&IB9lkAgNpe+v)LY3VKB`kEpsXoqh5pL03`p(6{wfH%B4B}7Mr3c* z!iNF|p3YVt4{R~``grW6rWufLf;T3b=P0dwIbztvXdL^z=N;b>s0MPt&I_89rEDHI~dlTk% zUMX!tX6SFv-fm53=`;`Cf3NB;UyymcQ>1b_2={F{^S%zxfCg(ftHG#=iBK9~BvM0y zdp+BUOxECj;noWh=I14HMc@QE)~ti;UQQkrzEPg(P0v6scgT(36lVb? z)!!BTG@*P6(4E!%qUmkh!X;gTpR&HLE+ z2%6jxgU?-g+oNmFHzCygpI{?;kv4jB!+OJ!@Yt2r!v5+NnVP4fw$Gq)9W`i^5lBMt zFY6oufh;{(w{wy@D5+vlWspYj{Y@EzA=GZis%j|MBISvS7WCQAxTwUJuo* z(XM(VBKT#Sb4FpQ#ecKmaZm?j#w*GD2O6kPg9W^ajP3oBC2hzAGFbKNm;VYL9`(bX zty@-m*Zf6EvDODDDY>0{%xN+-rcaf~uz($qhqtAlemhDZQe*#WzfAWV zUz*2DRm6bR3UkzIp1Ht4d456Dgb3WyG`VpcUtKw=q`qi*d*2#oFE&luX=r*-i)=r5 zSc4P{R*~U@S&22S+f!h{g6hEVBqVN>#<^0+C>;p97LfloKyeMktG?YUi&>6xmiCL0 z!dQu9q&WT07%50x2zht4Mv^Q)2`PO^o|E7b!c&Uc>_<~iv>{Wnc)ic6$oNB8`{WX8 zh%XB8LMKquR-0hw=IcpBhS>QUX4#HJL zRqaUayO_&s;~SEP>5Z)Y!3I!hGxUNoy+Y(Em|J2U8CRi2y_zR`rD1CcR#UM17!CZW z_c-|>KM~C8IdSM3gn9#tar#Db1xja|i^RphhMo+@UpS((1+H9xCs?;Ip$#~d_zDqV zL%f(KH;Y^jHVTezX;)pj>U?@`Ls1t)$6+mKiAZ$GPyoK{>vBA#=0*-wi z+EC8zs5!9~rb4xNA0R$$epKTq(dT-f?q5^xeDQ z;{4;*0i?-x(~ZNx@tX=Tv)^*_|0y-5=+AO>Nh6{7cGOKxGGZ|c zAoxbp@gGVhrkWVcnD=LIW5p(pegtY&;r(gUAWH`#D_=LXeS}K6DZa>lDg|CV#mKR% zADtZ=%A|jXL^zop`y?A&%LRv=jS{pR^Ocdp&&|zi1~!L`^7fJ*QyS7BMbXDg5d( zwMBhoH+{M%*GWQGERtj&j@H~<9v>_pe4@{*QK2*VmF>?I0DLN@b+Oxcd!2ccpKv7+ z$ncgPu*B7UlUu3P*XZgY6Pq&^>(TG!z{rBKx&?9qmC^8Ylzr;bxX?CXbxlCT%T{0R z>qi&*&4Hfqt@Hw}9loFrs|kxs9*MibYT^HSCKjh2Aq%8e8vs>5%G)Y7k z$yr(wp+=wLB3F)rJB`;?JsWe&#cZ+hw;uA3wzw%xBtliYrO$<6NGphQHTjMw-RJFH zaxR(BVV}i!Z-*Zzb@OB%Vf_f9;wN!g8UW1QtFQ;@VgLACXl)C5f>}-Chg%* zuOLX031kK8uhEX!H&p-@H17J(HaWq=rdv|YL6NQLJ-3T`fLkL$KPQ0Xmhi^VE^{zT zu!8mS-#u4|$*=sQUYRk;&{}P*&f_mdClVo03~s}qGO^o#)A%)Vh)*Xn1Mwf7ES(Xg zb$dp|Aw}8aG{o+Y+DqYr!HB77!)WNM%WAoN0Z%a`iR-tW2!rla8>}Sa{_RAS(*x5d zxDUjOne1U7MU+K9*ESyJ(bZL$b-}WW>+a~e5ncOpzK{JwE9sx7kN-&DYM|o%9j_#s zSGIqOo@W`E@BB5~|B&}C31u%K!88y!--=g_3Ej`=xiglwQo5KEV2g};XT85t0JeW4 znvqozCaLwL%!zH}p-#Nkt!n?$1nY`vuynN|-QU*h zKcv+Ld0~!Z>5XevEAhkznCdv+6R?0}T2s*nP3-mbG><;CG~@J^{UXC~0anzEljYE> zPq6DOq3m^mcIe9|B_l;I`7_ z8koE~sWU2LMX&taSK911Eyab!lKS|S%fs?F(MV#(pJV!e%dP<>EtJWWS=2Uho}w06 z>y8w+S9|!8b3mqVkkL(g_6efii+33$|RMc9f>ve?9suC=gfz*Unr>s zzcn;m)2oLGlP}eOEjUveo*uTJEUU-4?YRd0%Z*q2d{lTiVJcAUbg)pQ92#(QXJ87# zJ~p|X-30lF2zWLw-O+RZXrQ^4wDs%2TOzl8kA01i#nfdQMM`6i>r&t1+<(9iT+TZ9 z^LnDT0a&P(^ApByMuI$&jC3))YpLCMk&yUIz0*j?rkx8D zHx`5a`kKrtQpP--p$k(!u%tlfj9$7)1Qe%C#3$|=$PyXFIqn*Ygp~KQWu+G>(3_sW z{LI;m33`i+DKu!Q6M$_bKrQ={2Hg}Ui+_F+*rh8H5))6w|tskd8mibusEfmTgDt=$nI%NnA@$ z2zXX0Si>3qW6k65Rjuj3W^Gs4T*BK!1<(s73a4y<%x5`rvr-B`4OO z^~q_Gj?yDgOM*fS#Jwy1Y#-YiSzw)Y_d-1Xnz~e7oYVa7s@C}N50^_Fdz#I#@$sCe zgJuYS<`!~YE-Hm!x8!cFya2ZzGe2U`4`ih2UHyU|6s_(6>Z^I*^=Pv&#SLCMX0ub3 z`5pi1&|;B-AI8Lf#mHH|dd$aYiq$Z2St?b{os5{q>;ZpfxW*<~$O!OesIieR6jI*b zU+-|vzlJ}-HNb&mjT}U;?o9PLztRm)m#%{vW$)KS^pMg?F*!N1L> zU!DPXyv0Jv`Rvz*fcskR7tXeh1Rz0~2Y}f-e=G$fb>Hkldy-e{x~Fbt*dkRVKg&iM z7{M3_aeG8A%5Z_05hQxyMkw)3g;pSrjx?e#}96B847+{=fXlQOf;AkgAFVBLSjGP3R!WS_Makn^~2zSU2M z&u6L_n-P~TMHl#sy9c2%H0eBmScptB+GLBdVN$E*?5Bw57!1%7c4aHLeWc0|silo~ zE()~_$AR(2z4#)ro#kW@foiG(^SfLEZtDyDc#ktxWh-{Z9C}?g@!7*>*uX%<9ZsP` zzfknD!DbmW&`WAyD?uI|c;Ia(L_-sEK3UzqzP6lSJ#rwH(xH<_{uvlN+&!2dUa&nB zu<(wc-UQ*^wwY1>BEL09%-|)?B%XemiNH7DTCEOuOt5P=LQ&g*zmbo|BlmP>+3Cs? z-sI5iG!wfIrrZzeqt8laprg;s=(mZmoEy(HX8qFqe21!8-dEwA_JH1bmdav z1+)u}%M)>5BJhq1Uh6(SapCM_Y-lcxo2C5NgDF9tA%ZBjN!DDb%n&leAZREE08%^X zWQAp@DCI*9C1vF%+&SQ`zm$}eFAfD_SnFc=Z-#7R@&?```qRf)M&UPnl3A#GNz$3b z4jNGzOyFgd;6GBKpNKp zE6_*hWj8)Gg}JV}IZH_BiR%a-YXfd1gJ|3>d!=!xrk8j^n6I zc~v-#inr=Av||A5ao*+u+)0){2}TFKybXxVyO0NJ1v+FiVia!diN?*R+6X`w>%G6I zYLLl!kK?hX_n4}t779PXNZlTnU(d6R;V{n1F)XjB@VFTDxTx?rtB8$>ao9M)^}$9p98J0weem%w`2+1kE-!xb1eelk^7c#D-1fl6UscQf=cXK)mgS?M(sq`TNBvG}P6li`y3@L2ur?5t>sG7(-=^e8WDjY0H%_%P9#N zOKfWX?JHia(PbzV#9>HK1;6~Jv&jP_c|QO>TM_kl@&Z!v?c0YKp%{hhcOpa?^*Kbd z3Ba#HRE;R{l&! zv?hH^c|5f*1~tKN9j6{gkPDVJR@brdeIZd}mSnVvDoA_5lj$38l#k)NRt`+iG3sTz z_fLPtka%kdWG@~yYwJJF?RlH8=!1gxQ zzTl8SxT^^x=#dT!!M)D5Xva1iakY>Pq2tVmfxfR6AF#efcOo*a*+!yRB$!*KUko(f z=xQXVCNm*ymiFuGP0JXcn8@9fx&|sn8k5RKz_9hFi*?Vj?u9*u%pBNVjt%Rz6_SOT z*{RpuWhm=j0Eh*nk6u07=@hsBqa=knaRlW7ie!0y*Lfuq=CnYAny zfZIsO?(?bhq<~Th>Mb=Js=7;kEry3lZYvAxBs7I)yebC>w9tWV zc^pLwwMgqv8utJ_8`wX)xHvnCjW|UIYW5&)V9cYTz&;kC4s^cP{mKhhIJ@Xf>#hFY zT8CaC`MulonRPM~w{bDC!$mI>Obq|GP}f;uB>o1UL~zD1IwOW&`QX%KtXwCr!lZw@ zuwyk7M93>*oZ{v5<}Hx+fGYraLBUpUVSqn-qF(uOm2fc@;(k70t78l)(w=;fPsAAo zbolt1!$Lo$Kd2AlF9GfzV7=Ha0IoK4u6V4+&d7(DxTS7stwUd(I_;B_C`Q6uKWX|w z?>sd2I@eTF>ts#`paFq727qGkL|}&I=!AUBq3O1p{0kQcs=72ww*z$v=I0+ppn^mjhA!D2$+Ee=stnOH#Af!vhHV+0nM8a9Xy;*O_UQ zBizfjEX&Ms@qkc3`n6?|;>UrD9jdCLGBz<`a;m~RU+{Iyggy{w7ndAYG9DGobgjW2 z`7Qgt;~zurg5V7UaMjK@E9G{F9scxJmC^A1FNaz0nid>#3mj z^=~}D+InT+7T2%pT?54;HC;jEvrpUG_9PxhhwYi#+FGXgc4?dW8$tu<#GE`?;*=U+nIlpX`19{27ZJ z2PRBw{4xWijkM!&fq*CjwHFq7X<`JE0kOG^MO>FVe_XO99#94E+D8-#)1V;2YDsX&i{ zz9O4BG|&n!^1B!SP{AO!U1-MznxrrXnl#a|PXPAip)s((VeFt}fWpSsB9Xe$c`pPoh<>t4jtN`Jce z{dd^NW86#ax6*BQ)-qRx-?iRh6ZM0>9AGh^7o-8or-3q9c(Ys{Kpup%19hB)20(Vm zB2Eo)00si{W<>%YEC44HQ&ZEl4C7N3P%1mXkNVE@(Z8go#3DZ9YN}FcA&6~ zCGrb5kY8X1u#nDfhxcv5cz%LUx0*5IkjevWF>*x6QdDvnhFFFwR?E*}f&^(9K;fOK zD|G>-J^=V+KSF@sXKj1=kafB~FQfPow=V+=0qiE=S;c@szZ0Ws((_6N29!#D2h4(% zmZ7sj`py=h9W~r0B8LMz7MJ`bHw^^r%q^h36@JXn9pYw8Sinm*pf^soOmsP_RRl?ZSo1pRtf^4bRhrqU-fl z#|(Xcrx`P<1t>KmEFnBWFX)2&Tnyc}jrVjVy%a2n%8IgxCmCN>#vz0yNCJHLZjXf* z)kY8|xQY}nZhQJDcE_zL<5Me8jSo;x4I8kRap=0J^pC>Xf%C4&0Eqo2Fe-KLIaU@d zKjKe!AL@O>a0+J!1q=H5E~%=Y=aV-~`H|$Tx)4u@J70s-}i+^>+<{Bw7(}oS@Y6j&%@p0 z>N{~+>LW+LP@!A0rS&EK=TFj1(=JDx>nqskJyKXb!S~$5yZ-uK^-XH?eo_}(;9oA0gfxK}5b?=ShCkglBb*&5-5cp-`ch=Q_I zw2E7wfmfhsvphA5GlUpLLt6D57pLWa{mgoS(A4AweYQ#Xe0<(Jr8R(gU-r3k`& zs()$e>AskZ(`WUf&V+?&mfc%r_?BSoL0#3gR@{W(Gd`I4Q0<~!=z?2#5!-~ny@4*c zvpfd+dpgG3%o7Tt*dIRsH7@pj!<&8n?}zK2XFRgNI`WZAXcqFQG?*4u<%*6g+G;*F zAL~$qmif|+RG?ldHic-HnA@D4q=~&8#;uuik{)_@F6Oz zf@>=1glpVr=0acIITY(a%V$`uSb@HmZ4AC&_TWL|mv#m8n<-^mFO;5j zppHaqbWl0)MKM1?DB(2VHg8Upwv|RDlhhkUgnP2+)RK(Yo)cP;Uv2-ExBKTz;%XDV zn0JUDK^fjJniDH!MtbsZGJqY}+^DT-UK>{g;p71mZ)4(e7PU{=6hqlwxx#{o_ zX>6f4-G;IIND;E*-Pf~+uBVZTHIT9)JFwCRv|#-41yVA--1F|*@_%ck!=kAQP+(IHRK>C z1Q$&)Gpk>PSy8MJH^Zj>+3Z7x{rZ!U137p253#!HQx`3@>dXD-MU0$?KW9&VSM5#K zQDG;?Nx_qY@C=T}rkLqtrtM9 z^f||A5PevYOiA|*slDCB@<4Slo6lp(G!$>f8Y0wec80}6snqn!57)}SV7yV=ll}Uv zz;{>HAL_JxHx|-NGCPOVK!0k&rxmY`Vg~sljzn5Jjc7)qCu*n5xLRys$OX5-`XUPZ zwVOt1S}$C2*9Ba5a!dtIlFJQ%s!CE)nmTBWm}}pOV%ET?OKe~ z-^3tZQ-cxmEcNX#Ra+LrI)G4OeaZbTQ$}f*_{@23Yc2K9JT6S%;;&5c=YBxthH5D-a4< z+J?UR9QGJR<0H-8owjcC{WJ3bcJP^Ogzxp@cSQwJvmXsn>AN_>9%WC_X)u;NI1l)d z2CBlaC$7R!oI`F_pU|aSHa7p;rSDH?j>UFH!kDT!wa#k>y% z#Wk+QPiFVaY&{W=VTvT34U1>{X#B{-n5bCU2kw^Jo!5AJoWHR1B{4~$JNcj>Xusm2 z2C-W|@rgVps_~gI6;oF}>tb5jMZ-L$#EhalW>5Qt&T6R4AqVE=&Bns`BEyqYIVVg} zfzb7|n$gFs>E~xQ3CGn1;#;mKSuz$&wN0;RjoB*t>qN{^TTH3lUYRI~P!;OKFhA|n zcXEiQr<|V`Xt#ac_Y}7f(h#)}GB`#$s?t7>qarlmecZD-rtoAa1!AN7$bBxkY6`Cyg7)l#z8F>_;f4Z|vdwgrv zShep*=Xll3ho>_Uq1{u`nuW=F^xD!nkS(1Ul&-4#{k@7y96?bkQ&H^YtJ@s>5iXdm zC{@XDU`EebBM~bQWw6xawqsP;ZC6#4t|qkwl7{kN{fdR<+jC@bGn0*m`8?tGWQ*V1 zKOTlPq$-OPJSW;(&`PYbv+3A$vBAGZx;8aZHs$5?18JM~gOZ^~DaR|X3FZ7M5Su;q z+b)NVE^>?*XG;l$T6HI#yFUsAfLD^6MVeV|hvR&xd!&u2qZg2Qd7`;jhGoI zF<4+4RIf2uXh z!0RTMDQyRhdGDH7l$g(Wn|4Pg;GT|Z?t$Yxkv3S&vPT`oRLiY5?1oMKDKGTq0(Drz zcYfrkeUrm=&J*Nj&WgI_+z#hk<=hb^`X!ggEgt-r7xh~Fj^Z^8<^C1QJfwFAod@7C zwRqQUB0@7`odtY$GmSrUulcHm4tWnLehhYzP1tsF>EQy63$d0wp>QSYMDyIwHjszZ zTWjNs5s&*SL$ri7Odq?HUnD3*8*rh%iT46@#W${TiWTXaoc9**>r=_D^Ua;6mwrT! zQJ;*c3IqE}%ULF^NM^Y%W_o8GXO;QuPUp4U5j<@vRl7CE3^4-kTYYDUrSy3XW4MF{ zK`U*8J7iFGS`)+Jl~-8{VR~(HU9>}xO2mx?^9`3C?s8h%&v1_nLFS{<47a{c!p9#C z=HKT`AK5$&Km7cl-k{1yexds{v&ra5v))Vh0Ck+jEJ|$^Q>6b3nQ^T`g-|L6o~UNR z0t^Vk62h#t7pN<}kWRC4!UsQKv4DB%=sVOG$91#sy{&JvRuSXKCrRoGUcVis`(N@@ zvnLKa-$~IaDu;TCey}XQ#Fz$NyjO>avEgln#IVn^mz&`DZU|6yHf0A{ZjbZpGL`F5 z+Zu{!ZidGlP^voJtPS!|q7ib!VfC!iEBN}xet)Tx;|n2W&s!pP56HDDj0I}DYgYhO ziA1*fC^YF}A7L1K`Q1|BAp)`b;|u8yWfvWeZcQ|MsL;pSC;|o`^%cblv!_vrIfl+_lV3c z9RXh*1FX;OD||2*ZrH)`Wtg~Y<04t0U>pxHD9cC%Thdk^`V{>Uz8!&w**U#%Y~=d9t)p8*B@nOp2<<%?c&+7 zbJ>02LZp<9^k(7k_Q9q5aYpIX#Y5lNp*Jb@f_SPhmXKen1bkQMOHL?!+iNYJN+qQ(RY43a8zro0~g#GIgM9Z z#Cv_1|9Sq-JF8PN0`{&Uo2Nso%(pq8Q&S}D2oAZT<`F(Hfl0bkrD>2Nb%y&mP}JhX z?Y8eFQm06N!A*2pL=7Oyf}bl<%ghAm^y^XgT|Vvbke=K2HHXj!upI-j3{I5+$}d%V}z+|{xi(>yD{b(Eveb?isSS&I5eo|ewG1a@64 zGWjk&F=e^Dh_1j$QZ_}D;}fjgbp|H6(K@`WTF$UJb^HmU@ztX|M}sj`((J+DY(jmO zm7FByrFMv-`~(gof5d`@h_C+nc5z`E`+37yiR(o+FKT*9_Hrd)QbU0QCB{FXv}uUd z|Gm536&nb-Uh=e6Y4J65vQdr3P&etNxfIkc*UY#JV^|FyR8~{{sej>Kx(+v`Ce=gH zh=DH@a$CuJa!Q)aGIyR}KfA}0rI2taG>*f#Z1QQ(CN3o+D&M~MqPA7cCbV&7d6f&f zad1K`({I0J5l#5AQYMUdor!td;jq>pqNFJw=H?5Byi7--xE&7|W5azUnO`iW`mIpS zfu$qDZMFnw#zj|R?CEUH@ou+rjIYN<+UqV|lFdh-FjiItl%=>L(Q@7}eCnh`L@${s z=_%J2Zd`EfVwY7tSg06ES2PR>Tx`yN0i(K38UK!V`>oBP85c-oOuY8#+QyQ9oCJ=< z`s1z?H+AT?5S=MQFJbateThaB*g0IaHo%h&yOYyEXGUh=8en;`5g&D){6^?2HY=7@ zaYZD$S;XvO$0fkqX}3EvJ)7h%bF=XOrA8W4JAm=GpE9SpTAv zjfgAL;^5`Z6|DJ&a+EH>@E{`oHD8Ih;UTP@n@TN)z3HvYd97}W=!E}y-c$Irwv2~C z-?nit9L+Nt)_vFhZi?j(iz$o1GP@k!mKkm`{)~;6qFz1XX83hrrpOYne|A;g(JtUGCbD*>W zLxZ*ac4m(Ee)Zx7QXLA)HgpxwwhhTW^Is$&b+%UN{Nu3h!h_O|-?DaFsQ&JdF4Myg zdhr_geCAm0{lP;{QmKiOu%O9XHlEB*2r@(ecF%;!<@JsaI~G>rYDVN0vhq86X4GWS zHg)n%uhgLB4FgRU!oyhwUN(ccoOQORwJG)6b%n032QBsI=Z+x)wu??X%8VZ8Q)x#R z-C`|YC;0N#OiujWGX#dS%0-sPiodX(I#9j78<<~PV4~;bYchOok;!x`vR`wwhxOU+ z2E1e3cBIIdP-)HP)fsojdX~qlM{3mMacXLUThzr@Q*~S0$?LL^SuP><#9Kt3z>ON2 z)iy_LSoNMZOFLd6S$2w3rZjLk)>Ep*JNvKg(^?DgBI>kFue(VF>Z@DUluL#S&Dy$z`m!FyfZ)K!QCzmt;+32Fb>7>L>kI6 zwtu~@YTm18*w_YGEgs8a6Cm$7vOiIGXE2;{9T@9QJdtHWk5Q$O=@NZyno7sR9uWFi zj3=%1U4C`^`A>f}*@Zs7_22xwFYPDMpRhHXH4Ww~RRnPrQyZ0^o@$0DT2t zeq1ExLho6Apb!0Z4mRT7Z~OQSFFmqd(>u<;S@6eGwVZa899+F{hLi2qN!lh9ww9ox zWh1FftZaUv5f5D8g$zhAPy?Lt{|$LWX=KGuD2=F*7f*!GN?K%OtP8GIwiobHU&5q# zRAbMqBA8_oUSu79!E6tYS8qCBGwCEWP8Wm0p(efkSSjj^T+f=dZ zj3*BH&Nhh4CwuqrUnnab=raA#=0lx~;^1pTqDf#r2KTwpHU1V%>2qDN%r&Hr!fHBj zAE3cM==C~dzg~p5ZabqWRFlY{CEqJ8Me!Q&)d`MX4srG`U1aCpa{@ReK}9{yyX`v? zNV||hNxftj{-iuTu4_JTyj5yZpqVeTywAqyU zAbGAqSFUP`vV?Nhy(MQ_%lDL}O>B|PYBkGMj1`qaZ$cZ90P~QWjSD^L?}HBM6R@YY zmi6lm-jJ{BK5dA4#G@m{5L_~F!%xD*QmwFKw_sB$Q(Cu#VfOs-V4Z9=I(%2A{6!LH z3lf^~kfz*ifWmGdTbesp>G# zFoWN&za?$fHqw;4Y=PJz`R|dZX(00SVUG)4b?FxvnIJo5HT-*9&x)Itgs_ETewjlw zApxa;zqNoO=Fm;r^(XcvxY8yGM1r_N-f`(8ZRz)R70TajUqx`8Y1?pHW8Rc}@|u=4 z--X?Kz5VjO_Ow0nw1y(q3dDhb#?Zc)j(&9k*-~0$WNj~2t@NWtQ?1?@|HUyX0cX=!`53#M=3YruF^}g!l1AK$^*6;EW>V+ zSk8z*Mu~%Pvjn;|T7E54w~U?6L+5@gQhQR-PF{8FP|7-mXFEX+E#RcdC)9A{ySTpXXl!j@QnMck_%9zda2asnwJqHth0PW^lpNvlHb zLoZmShM_c~$7e6=lVF=B9gtdTaIK=tbkp%~QDJz$W=p87d9$aTx98NxKm(&AXO3mb zu5_KZaO^?CxVa2Uy{&%^OG3;~#Jjk4AcXl1?1k=wW0HJ@g+`+=-on!M=yON7`2b26 zKDaeGooTS^Q6Mp~Z(ze#<@P_?N_|Z(*?1s(m>g)Hn&k`;8fQ`8rg39?btzpbM@cOG z>N(eT7WDzF`GV>3KCE&YU?=v%V_x&iaMwm#yuMn@&yv|LOG_lr5n;w0O?dluyhsbmzN5Joy&@Rgg%LMyH!&(f zsPl!tQ~_+u(`MG@b`^t5#Z~W>i9`E<%P!YD%t<=(WSwiK`WtSw@uFy5;%uIZtvaO)Zao1CtRiLQJ*D1Xa5s*Bf7@eI zPKelcO-t+U?cg@-JVn4(WMg^#y9z+=fd|AAa41w<0J)VVLH`*aelQC96QNbtrB0Ml z7h(QrqV}Hga3v5%U%J$3>=1ntUg{%nB;P@OhN?K3NPM~0md-U{>3z>$ieCX3p)Trw zYAa3PbB@Mo>SU^&ya1Ep-LcBLwHcdwBXtvr-0}O-3X%y3xVo$Aq=JP(0MsrS%gOnm z7^(bmjXxvL?Hmn%X=E71X-cK*sWK=3`HY9kz1uvHY}b5UhyjrUV>3g#@frQ`$G5%% z?8~e1&TaUyG!Tmp<-!k6oWOo6*xmH~QH5>BUmIbI71a41+^nCze`1#QRgCRhB1IuP z@$-^oc>TM*@5s<#JH`c$>pB>xmi>5ZQcK{h)wt+^resQ2Fwelbn++-Hk&9pKTH!aA zq!wMN)3*(8L(u6gWzJ<1zQ1n`!_h8{K!6@=#g{Q`PA9YRiEv-c9VIJr3s-#iOf5_llTz$1LuTGc1IuoD>UV8wfuJZq$M=qa&+AC5kN z3g?JZx`ePuu?b;N6mk+j2mdlrVfRjP>JJxD2uC#QoSu}IAnA@bu%irIxJ z4v*c+cJ++au@qtAT6dYVZ3!ppX!ndivfJ{e@q$=Ae@fH>&+bMQs_lLOi~%Ap8n+Ht zq@gtWZDosvF25#kQG9jYI4*;S2Zsd4>Mkl+i>=EM-;2|zstWudUQnq1gVr$qAz~Foe)t`s)@B8UCO-d9?mUx7LqZJz6j*6 ze`PHe)IE=vAHa{gVpPNSdvTQP9=>1`@{Pc?>bUVUn6cu~yN5>ZZoK&;lLo~Fpm#C1 zNE(#TwZf=siC6XTOda1-DQB!0ufvGzNd&k%(Fb)ZVYAUAwFRU#=l41a{c1$FBO=mE z%H=mvFg!@2w9w(Co3TcmtoUxP%58*UMh_q?zQ}lc2&34OI8$xTV#6**mKMwobTSFi zhR66hPyHi2(ijpf2 zh#>1wIvJRXFHHwpP+Wg1@HUwnH$lZK(FvwuFAhFHZ!Q^1h^~mU3AMRjTW&<=e*nSo zcC$JjyI|)1!&8@^h0wF&8=l5XHcYst{4k@VrPt$eSbKyNCs3bP4` z{aJQ*lC2%7Uhk&IEguX#SDU5dloC*rFmy$GPC0Bs92d6C(xs{i*Al_G1MM@>kKd0S z-&&`8F$e7Pp&t76E$zpemQ)gNdJIC^3*5pl;7{4e^PR{#alt?HO=2;WgxwtN1XQmL z2&4(XRFoS)azd2t`V;7t@_tIkip_MQe&cVxHSxLlg_2Y5R+LsVFZkrIt+KJj8kh;9 zYk@7W0>8GSBEA+YeTBz|`g|f$ab6c8yD zB26!=W5Ih-2U8b$$a9ZMe#PFP^I9s(%E+L1Qq))B_uPBnSLg9EB2xjT9BXs-4h+`H zBKdr}qVd>O9|F#RWX>vCBikss&#);HpFEpskz^AxMh>#(02{Z8gf+3+YZ~ZEe)R6J+l;sl zAKaME){&HWuVLV>pQy;J74sleB;k8ayFG(hOWUq0f3kzih|MkJAS!`~5Sx&QmVzX=h{;Zag%WgymuSx|GRA>`c8}%*s(wyPOyzIN+ChA_p5vOsa?1 z0cl8G)ISbPT9ZawkeoZEOX)|d65~bxp(IRrBEFPNT4Obv zeNu!!t`TN!azyy^*fNHTyvXERWo#SA>mODbBkp?G2VnA5_1IuGw)rwZ(XuqHE=-KP zLw!0{#g#dh1EWH_*z&Lye}S(*=u`3zxF4tf_+rF;NRcEzD(p^*G!5@;L0-;-iXq>@ zF=@bM_u6J)G$x@gMGy%g>wce#jur;LF|;TlJJRMG#!D zWPSJD0VA<+1}8N9lfwP>h8Qq`yD_4mvg$v2OC~8t5nZ9t-`UIsFL$R;?|xqr88BdC;=ffaS*%L> z^nfbn)&4Oz%u*sI5_tne^0u7u8{m>crWURLXgbvyjj@%u0BXnAMI6UN*wunst;~bZ zdid>j4}v3=Ig@LP9}*mz7X(CiLSpF1%(_=jTp$bNK6FRa%*&41UOc2Np;UQEytaoh zFKcZofdiHi6}eewOrRoJ6g6a@nGKtWb?`yv!u_#QNzIw(K6Dt7RMd8pzqPJL_+~~! zZgvjsc2@ljV;{GS$NOy>ji|Xqu~|yBz97z6)Rp;>1v^*6w;!AWS-U6O z7$BhpnKK%~EFm)xaMR3Q(M8Uzj;;=5C#-RXfh9@`ABnYj! z2Ek*!STE0b(~f95+lIqqvxoNZW&1I~4Z2a{mL-js%{O%}cilAl;5S+3xht=jci1~_n;#%Ug0(uXahMVVc$W-t=AcoPx8wL?_L4eiPG7+E*myEW zUpj}TyV#@O4jcLoRvTVyLpSG4Oh3a9_3$c?87({E zd>=2$h`_^ep4g;)7*#cUOmeb9h1SiM75Dwtbk6c|Mv{ zoPXqCm5X|jeORtW6fy35{z47^F@V4O8jdKxqOjRw;mn|<<~3>!z=1A3bBcp%x)n+D zf)LtS^K{9KU7*qM#Al!q;`>4Z@MOku{)CA##^7@0@L4Q;^3{n}oGf!=hy_IHeB^(qo(`H?2H;DZjDeMo^WHUaG3~agTm@x{;VTv_uZ9*NRis zj){D@kgOUq6YSPUj7Up+oCa}$ja!Y~A295OxGL0L&wb2R@x5Ocbzk#)|LsMOF_%ux ziCBRbEJuUEs;XWrc?Z&MQY8uUW1fn9zyViG$nc%3+ui)wQ|GK__vY7_+DaJR!dhg` z**K9}86`n3qnbgh8mSm_s5amH{dmT>7cM2e3KA2%G4(Ec_I=8m{A=45JO%@_m!_H>$y4G(AxADLVefS*~k)6Fw^Uk5efW?rn!4E ziQ{SI1I$S&J(r(*w+s8rIZ0eKWjrf~MGWp=^In;31QGgIeJjAAa&4l0n@(69dCKbCDXm0>pzZeIKvYZ`qRY+C;~_Dl-vl$R@!({!MXu=<*hx z*>PnKerD0^T#SU=jU~2Tj_oL;P8^ju#`C2nQ3uJk;1XB)kIFj*X%#YZbRR(1afJyh zXMcpy`W5UrEWI&@fHY8r5c<=Xa2wBN{;+d!kOZ-$W>Z!-`$KRvW7(m^hThPL;SiO& zI#6mDS*|V8(p1;2S*kXS8X108F>}E*GxFf$p!C3)wi|VELRUC@*JkhGecUfeon_+d z?4TqACwWzbBR;$Oj^U7u^5)ALF%?L5f-YAuJfM#m5BrG}|0yf6t+59^;Qrv&Cb8uj zkam=wM}k+#qKG=XJGt`r+=s}gO2SLIy<+T-ucX|izVuj%(f*nDqb6clBWJwa;q%>! zA);^cHf$0i=+xe_lhj^rtvsB-z9~@&1w^7nD9t4*7t&1r)2#klKeL(ktxQdsJ>G!K z%3iC1v8kIuv!OJmCuzUmM{^KRh3MON{9g5`o`Ln{X{+~YT#kLyoH&)!dk9VQXQ+iX z?A)BFzf#fX%UIhcH^_#}vN5K$9KP52LL98@8?drL%wT0xz{R0YuQ{`Lc!1lV2L}gn zqwxw^fm}iTPJa+6VuofKv`hInkw#$YbuWE>hrS8BW^82z>@0-Uy}f7kQS5{*bUi$e_;q&Bw)9Z;}rxV4&L|m98Qd zL>7lxGrn_McG%&^9(fOLC~t(}$=BgoG0$GS$pz8@#xmQS^!;h%`&NJd`a%4Z6HW_J z!wa_gUu+XN6{KLD$*mZ%t3f88iB{Z0Z_xcye`C>0SXa;a(}9?8sI+1m=Qd;J{)!^r znaMnCCmd<<1|_SbubF)3GqJ{mupB_tIXn!c;iB*L^>_o)By2xk;dqK|1=;J9!mhT) z8uKS5;g>cZZU-Xr(;e3Gp%7vYB>c^_a zW@a=|h?}=mf;-`6cK+0nr2-^&*!QS9Lpr&k4H}ema(c&jT4-Z;-5Pn2l5N=fBcgeS~$#l8RV!Ap?x zP%RaWOLLQXg<&OfGQB=v5PBK`om#-D#x6aNUanstQC47v!oUZtm)0rtdQIF!U4+&= zE+U!4ZBg(C3pPm?O4Aad?X-bC=C6Z~UNLVR0T_IhphWW58DS%vU|PO3?1=)VF}x?e zMN+6Sz2z+}xw&Ns)G4otPa5@*5WFYLz|6?n;zs6;w}q|kq=t&n@|-8G3f|WNxf3Sm z4SZGzX)OZX!3Klv`tzWsip?nmsFh3WEFztuA0S)xZtg`jeCN#y>V0i@HmVE7oHiQy ztYQZ30)M^tU!IhlBnYZ;<>mCu@`XcdUkD)6xYa!2EH}(3a_qBx-t}FEY*5Yf@OA1%7m1$IX4-pbB4$+-JLm;f;Z9V(?GHC197jGm*$%wC8vI~ z@1FAmIuA$nJjAfu`OW;(S0oiAtqi&9WqXv|CKq7F*M=`S{>F z%gMTt9hp7XYqIP_u8@MVuW-DldAkPMM`iizojtobRFnYB-Yg22M%d`=su65?;Ja8g z33;BNqq2|9(>s*ovvGRV=h&{36E#M=pvqpy+SN2a^jZ1FOdSF|N-8F{sq7-kGE- z4|2DuQPNQj-8$?29113%$xrcwhDh6<2~Z^*TwO10lxGN@o;rCNiby%9ZBL2bPPMAZ z1*_7b%f!D_x&hs9nvz0<=}Ja;(O*h4r_=I*dUf8<9Wagl^;s)D`ca_!%SJbwO@=W% z0vNnt*l7^(1I$>1dK%NB&_7!wlon@Z1nh|3Xzn~E3xHcz{``&IbMfDT*36V=N_s__ zHB-@Kl7dB$l7REliODIbtY+gAk1+-9mtH^5y@K%D(ighin7nSj(5_M<+%G_BVl}^7 z(T}5f_M)r0F#2e#lTBv(ds@rIlA z{*pP#oo(nwd)Ny{Dbz1w413W0p7u|#MNT7~-GOjF=YyS(O$@%vZOMmABR^l(?Aw>_ zy>xR(t6qz6-|DH`)~N9*d3v@BORlvudnds8M`OiP6S=vDbb&2t6xRlcv8E+{`H3bJ~AU@^W)+DAAEJ& z)~0?gOX_B+?z<5}<<-=l{9)=BO{8ndijxx~*rcD~-|v1{=`8?RW!=s&^VJW*EbYj} z>;*#Rx@M(yh9$o-JiVs9`iFqxCad9FX>UcA5ZhBd zgA(YSJs5^4D5|^D^Q`YCQ|s!*vS6Q8bq;JQ>eITmo&wBuklEe$16%dZ&B+6B_nQk^>9gx_>F2uft$-2Bh6TXH>0>E&azOFwdHW%OA0iAU)9EocSeec$DT zb38{R3SwV5=7c9LC|*rtHh~NCl#2>2L>1xm6NtG3)l^!+vUIX#j_$NFP|wAP|B&x< zhR@FeFV!my^u9Y(qxIxsdk4{eE80{;^)9Ys_kJ3W*8iGa=_g6o_4%H0HP0<+V9|Ud zjtfeVhhT>8VNQV{IHGhxF<-w)Dnudh2Z`3slO_amL^C~(bi%aE`#y5l*iq)zIojRH z$-d%9$;Z1l=TV1>oZg#PGitWXQ!{qHw?=~a`THH|hci@%+k0DwzT0EWt4lnVTu%JD3C4?(QLY zdcy0?wr9Q)*DgCsa*qqAjj&aJoiVP}Pq`*Qh!s&4Yba-QLmwM!V>^`Kc)$wyt0~<& z8|?UtQjSU=t`VBKjj5D{(LgS9E~W61juml#1xK5RE~tRH|8k;7ZFign%JF%-uefNy zrMrGxxXj!1U`S0x`m;vK$7Y{Q(%LxR`9QNbi-cPe?q8;GjKv;K0@`Wwh6@+Qb*#M* zXlkr{Sk}(Pd!}2>F!oy1O7hAK(&~Uq5yB&H3nR0Jehx&R<65D~_Q*oMFgQNtV}D8F zv1g_U?9gXA^lf9;gjC7KfU}=`nsf7gvLg_>F>_*&@xwAIcqFxOx7}JA-{-e$%8Zv& zRUdOc&z^ncHA1f-afdxxcJ&)eNyzR^0foI>ub;(>Ok%t9`#o0<8z+3F_xAglH3^&t zhZ?~ll`oA#0ebv!B4LzlCGig`1m$BCOb<#eBOFj3UxenMf$r^WU2f2tLw5DxZEkB$ zmmSNcG)Gh!)!QBokInc;*K%d%@vLidSvgTkP7(l#+-v1y2rhb!5f&88zF=Z%n=94D ziS9WyY^LDR9o*Jih`yZH(T#K%KL-oX)Y zD3pl=1`i;RLJine+mxd>D>uPvxrR?{i;}2SAL`U;DMpJqR^eGoe`#de6UVhS) zP)oAz20NcrD?2!cgTv}%2D3{O7v2C&fb-W|PAo0Yqo2)j4mr?*BkbCg*g3db{AD?A zJ^$UC`;)~d;+K$9+B+_prJM6xApk|N3w8Yw)|y?NUbq2ZAFK?WNbobv>A&S+N{#E- zWrW5{Efj(R;8a}%U z5GWcwmDLIt)Ff;4soy_KooY3=%s`wy+u@Ag7+b-+-2EL9>w2ex*E)DL<(F5hV7Ok(c0DsyLX5+dJCS@g5c4Ipup)lb4B zS8*3QA5I6Zzv4_>Z#V%7e@MbtUPbIaJSQQEw`wn}m9br}VEFO`kr~fMt|ArEqeI>P zPMAbal6%Hb|9r|*DCJQ|BFm48#EyiawJ=o>)BZ0Fx06Hk3M6Ey*?#;gYgJ;yeO%wG zAj^2?LYLmG!oj;$k@NJ4T}ZPcV>HAzM2dEa>u6jTxttjE5xxDmi5%hDJ#zSprCw;VW5OF{BsqSB{e zwh($98T(i<&wOQldE!&~d=Mx6D>I9T0J*>aZnplRT;kC0? zc?6={W%;XJLTPWQY-IS>5u__ITwaoj3?&?2KOD0?n=nZwL2Ch_7B;$g2Ez~k%5Xp- z*WSQrZ+|i2|N1uqtO24kSSdj_@qML2U(!f>-*0eR0Q50icVBOKfR}-0Nz!TjRkWT6 zbiD?BXU&)Yi{Id_`ff`jZx8)m9KJl2r6tN+R%e5@@9wVyp{6F#oLRlmuZ z6>)vzCEt@E zrRBN5phHmd(fH5#8DHb+8QG88Ujn-JFmS#3|P3;AZ?kNdE6W`dFC$t zzsD;T*g+W}7ortu&ONg%CEbdAO2bCWF~}U(KwXq#a$N?*{&BDRmbFC8=}YrSuHb6_ zz(p%UHZ`Ot%1O*z@v`SzzwZmBGasXFi-=w^LVHdx^r5Ef64=UZU6QnU?Kmi~LKD>T z;IV_TE`f1nO`1L!^dT2Xb-6Q|iDM&=3uP8I^Cp#MsBrpnp!)<|A9Xs~BoeRIax~|D zMPejgev^bV(60YP3gvcD1%M@XrWjoN`uBQq9S=H6 z{er6A4lrj&BJjlxJ5STyXoo{lN}}8xpH1(&m^_1R4&$TC*8VeN7zBh*otN@MUhHMhCUc{knaj3NokFZlbH3&@Wz6< z76g$);}vxCDyun{a9Z2_)>qIj+}k8(jb#BoeW+5t2+OdwpPXAS3!`{*6E{QdvuLN3 zrRe6EHVH4{bg7dl*9slNLW@KQfeOjO13=1*tbKKa*1+irwk8GD!ZF*#ow`yih`@RUDcr75x4klc@Ts($)be@EyovI61^~mp41a@ICi?zbcqp3M z2T^ot3i0iCuWhr^GH@M_xvk>Iy3B7zQ%DpC0{}yR8SQ!-3gh;uYOr$$X;$*;@ys7_2YivQ8#@D zTy%!Ax|`)SEqRxSsYR&>7(_5ARwXo}0I7I4y_LGm*aD>_AOK1*=cm5$zD?69DB`*j zX3!)&>bx#?Lml<4Sr3}OE^3NW>c-6MFWG_K{ddCHp-nznHqh)eu5o+glZ_D&*++mS zaXGap*|^(oD4nJ}Wq7?`D`ya;g0FICCumS|$Qs+rKyKK=xMUTL`<@2xp(+IPhAD>)ts zsG*OktBtoPFcTh%beH*cp?`M%GZQ_EyF9zsl{#_LV-?P(heew%JHfw8=^+*(HGFmQ;>%F( zwnZ{ljBF(f9O&cne<0bUD#pKiGRL9fcDw^5*@?b47Kr5Wil~2*=0A|r{c2klil{bb zzk6#ZLEZGt=0ojZtv9Ac427MqRwaLaEiPmD4;|Dk&L5N(wM7|=F%EyL1~E+BsjafS zaxjq1er>>L=^OuZDaiSb1bTi*x82*}XU`H#s|5=Qv)^w}=JS~M{VqEuuu zjcNcX3E7E(44AS08S`UbRdSbnx`eoGtc`V6S3r4$+>@JG}CAx^Wh8(GJnuya3{=iW4;_C9iDh}#ny;aCxh$hj)7 z>Q&BwD*<5u#%o{na3lX1txL@YthsH;Zz{ICh%>s@QvxoyH2A5H}dH{UM7dqBT>IFhGJU20rvo4L=)ZxHn^aUKhDIu$S==_^d&a5M&FgD zf;w<#yr8(TJguF#)cJy|@)p^<VW%{2gU4flPeDCUg7J8-q^0-(Lz~~Z>X3UTh$2=K(0YJ+pI88e+*<-A=M1R3fKr@C7{`}Qb>W`0Y!nl9vf8s6bGiPXV zFu0O_OKa=+U<#T+kLSaYd2+J4>h1kwO_!bo%r*ddWb@Rk9n^c9y&gU5?jVHcpnKaW z=ONxP(r%-(Sfcr@+>O>&0@c(ogBuJPjr#3LR?{FDl!-Q-dOP}ng2Jy1LUgRYjHm0P zG_H@F6PRKA2V+H5N&c;L<70R0VY`ZFD8r&;<>b!u1Qc16YD`h#ab3bVxu^VLuJ-A} zRz1xYFi0QLbWMlf_y@lvqlabT)dW5g_KZG z8qx#m7J;8_F-Mvobf=lEoPR!^Pq!sP99x4gElp(b-dYJ!u}iZEi;AZ4jE|O>4Eew5 zy8!C^orw!m<$oNsOcT&#H;zwTqJL1I>sFpaa7(XX)*tb6Q01zOhBtp~o6A6Hef|O1Z1Ve~rSp5M6iH>p^WV7| z;wW7}V)30^roazceV#pi?g>J{6H0Wy3b6GBu5SJ8`*|4S2^e+=*&m~hs`CANWOd&c zg+4fqb!d&C9*0r-MQ9#11ac464zn4EPGw5qrS4}E6E=swB|;mx|8H!)R4j5sc-i9} zJhs+VcKJM_>^}6>GdV2fTI%tXl4K#(x+>)IX2{}R-*vnr`K~@AdtD@5I{>>*y&Sj- z?!sSl1W|r_Rnu`<=D+&fp&Uasu!|25BvQhWfae=>F^Qn3bbFhAW%FMr^L*TG=8H%A*Wev8+hw)amQFyUzTOam82mB^AE zUkEww$VwBfH(xuAafS&k7t6^;a*YcYTA@q}_->a^C%F=AmY5u?bloBDJrSf6G)Im6 z7}t9PFDOZ-5a^ftFN|NJ0~r6{-0_P-?KUF64+wfkpGo};k8in+ZW9MP!&gxAN<3x3c*1- zIZNrePqXt55?pePRjk7 zTFI#w_M#jcV*>sUZ=!|A;@`73a?5n{ z;HAnq6#3y8{~mE=vY2Q@!86n?L3TWp5+v2(eZG|?Z%G6}$b!bbz9h>7U+81yNzI-%)=h6XubMRBGE6BGfAU2PQ;DVab zP;%yQG4*c1_b)mRilEK7R&`P$s`?>78qojI#eb0G5JT(7aC~pmOB+2z+Rs`bUOf@3 z6q@TO>Io|{h`eK5`X*G22wd_*@-LjaIz&Ru^zJa|w#dtL@y&&MASr0X;f_b>opgBb z?XH%tM^a|@uEn>Zl*l1#nY8T9_HBEa7LD+OPX#oP84>jPZBqkmGr*^J}{S& zPA6oN2tBiiTc!3A#HS*8yUK`OeO@T28X1rL%=W89S^@&20I^F8tt&$hYjZr-Y6r#d z7*r~w&(ktAJFE)>OAy70x6)pf;Bxo(+AEry*&`=hgJJ11cECAU#|Ll3SF^lMGKWVe z(wPEC=eTrM@CNSjIYPbM8nLdFwc`Lxk*U zc|77NWi-Pl5S^TQ+ckqDcHa7cBGJ=eEt^ttb@l&Z zduag(Eb$VwaFI$D^$`0XEHdOjZi|oR^CQvlXJ`O0 zYlIl@t_2X<@=b_Sjp|~G5qG88$m@m*D+$K;k(Y~icrE2ZP{B`FKHVHi%+hrDBpNjk z_8hs(YnsGqFv$Fm@$x$QeC*#h*N$eWex^kqeW1xI=3y4x4Eb&Su1f<-sC*vk z@uc4Kg;0z3a|JF5HftA7YsEJz{(_u|p43ACJsYC+8-e>UJ95>5k6j&Do0%>^sg$8T z51EP|fuCBsn?ses4R+V@b@@SX*@mvG>nXN|Lm z8HXAJ@*<5os)a!iBh9a`^6p;z8cuYK=)Ty-C|`Zr3+n`i8Il5dRQ}Qh35qBq+$N|N z#l1Xu!KlEIWrp!T6yJY~7>8u9yUrd-_nyj7#A+wdLkvXH(rJ3oMnaV4jAf@*EM6ke z+!+OpeR2xAM+gvYZ#pkPHpDp4=7@jceA>}Fton}w1cuF_L;{djI3mo9<3aWNsBNi^ z#{&DMA%ajOA9?{=ZEJFJ?=_k6&cO2}MMRiDDQXP0z7$213twC(@1A`>K%c`|X;=2v zY;AeF=5;b83T+rzW0DZ}oqw~^3)6XJ&o3hk`TUu!?K{aw!cCNwad8n<^G4r>njM0k z34?qrk66^Vkd|+|ckB-8htnLe_=Et9PoFXm`wPX-WHY-%Da{@n4A1lOQ}(=k%izvU z7`iFTXU(P7e$4Gu>2>)F17s8;6^B^Id&!p{6=80Mj<2X#O+R27t z#wp4HEu=5eiaHVb1gq+U?xn8n-@232rtLXGxT{E~B`h2!Vq-7d7)XrA%TccT`eS?{ z(;QeDBHoA5%wtRKzWobN{3@`i`BdK3#3`pHS$ni1YEjGIc;esn4!tvb82rgqQ9=Tu zd=0%UPFkpHo8wL5BE2_D%SU4wi>w`&nRh-}%;aUA3xe#$=TVah6&vyT8joUr;STM| z4o5#K>S2eDOrrPbAKoT-5mHer@?++9oQSP>{ur>&#cVIIevS!VE7D_s3+cHeE$wp2 zI!{mblg`ri9SXLp9d8N9WhW(Id->Bwaeg|y$9T#Hvjo2e#BIVclSP+chS8Ey)yyBh z`AB-Hk0eumy?@pA9&_*Yq4$mnULK2iU@$K#6He>CDq0EC~2KFi|5|SeFCQ=5koX z5H*OfYV-m3SfjrJ_)}OWG8u$04Uk|u0_BF$f7kFqU19X!)6<|rG5Sws?GR@@O#FM- Sl~`f)|MIdbw@Rc<9{(RdGq(Q# diff --git a/bridge/etc/bridge.ucls b/bridge/etc/bridge.ucls deleted file mode 100644 index 2eda6e1d1..000000000 --- a/bridge/etc/bridge.ucls +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/bridge/etc/bridge.urm.puml b/bridge/etc/bridge.urm.puml deleted file mode 100644 index 82e3b14af..000000000 --- a/bridge/etc/bridge.urm.puml +++ /dev/null @@ -1,92 +0,0 @@ -@startuml -package com.iluwatar.bridge { - class App { - + App() - + main(args : String[]) {static} - } - class BlindingMagicWeapon { - + BlindingMagicWeapon(imp : BlindingMagicWeaponImpl) - + blind() - + getImp() : BlindingMagicWeaponImpl - + swing() - + unwield() - + wield() - } - abstract class BlindingMagicWeaponImpl { - + BlindingMagicWeaponImpl() - + blindImp() {abstract} - } - class Excalibur { - - LOGGER : Logger {static} - + Excalibur() - + blindImp() - + swingImp() - + unwieldImp() - + wieldImp() - } - class FlyingMagicWeapon { - + FlyingMagicWeapon(imp : FlyingMagicWeaponImpl) - + fly() - + getImp() : FlyingMagicWeaponImpl - + swing() - + unwield() - + wield() - } - abstract class FlyingMagicWeaponImpl { - + FlyingMagicWeaponImpl() - + flyImp() {abstract} - } - abstract class MagicWeapon { - # imp : MagicWeaponImpl - + MagicWeapon(imp : MagicWeaponImpl) - + getImp() : MagicWeaponImpl - + swing() {abstract} - + unwield() {abstract} - + wield() {abstract} - } - abstract class MagicWeaponImpl { - + MagicWeaponImpl() - + swingImp() {abstract} - + unwieldImp() {abstract} - + wieldImp() {abstract} - } - class Mjollnir { - - LOGGER : Logger {static} - + Mjollnir() - + flyImp() - + swingImp() - + unwieldImp() - + wieldImp() - } - class SoulEatingMagicWeapon { - + SoulEatingMagicWeapon(imp : SoulEatingMagicWeaponImpl) - + eatSoul() - + getImp() : SoulEatingMagicWeaponImpl - + swing() - + unwield() - + wield() - } - abstract class SoulEatingMagicWeaponImpl { - + SoulEatingMagicWeaponImpl() - + eatSoulImp() {abstract} - } - class Stormbringer { - - LOGGER : Logger {static} - + Stormbringer() - + eatSoulImp() - + swingImp() - + unwieldImp() - + wieldImp() - } -} -MagicWeapon --> "-imp" MagicWeaponImpl -BlindingMagicWeapon --|> MagicWeapon -BlindingMagicWeaponImpl --|> MagicWeaponImpl -Excalibur --|> BlindingMagicWeaponImpl -FlyingMagicWeapon --|> MagicWeapon -FlyingMagicWeaponImpl --|> MagicWeaponImpl -Mjollnir --|> FlyingMagicWeaponImpl -SoulEatingMagicWeapon --|> MagicWeapon -SoulEatingMagicWeaponImpl --|> MagicWeaponImpl -Stormbringer --|> SoulEatingMagicWeaponImpl -@enduml \ No newline at end of file diff --git a/bridge/src/main/java/com/iluwatar/bridge/App.java b/bridge/src/main/java/com/iluwatar/bridge/App.java index 4fc336042..c986de656 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/App.java +++ b/bridge/src/main/java/com/iluwatar/bridge/App.java @@ -22,40 +22,42 @@ */ package com.iluwatar.bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * - * The Bridge pattern can also be thought of as two layers of abstraction. With Bridge, you can - * decouple an abstraction from its implementation so that the two can vary independently. + * Composition over inheritance. The Bridge pattern can also be thought of as two layers of abstraction. + * With Bridge, you can decouple an abstraction from its implementation so that the two can vary independently. *

      - * In Bridge pattern both abstraction ({@link MagicWeapon}) and implementation ( - * {@link MagicWeaponImpl}) have their own class hierarchies. The interface of the implementations + * In Bridge pattern both abstraction ({@link Weapon}) and implementation ( + * {@link Enchantment}) have their own class hierarchies. The interface of the implementations * can be changed without affecting the clients. + *

      + * In this example we have two class hierarchies. One of weapons and another one of enchantments. We can easily + * combine any weapon with any enchantment using composition instead of creating deep class hierarchy. * */ public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + /** * Program entry point * * @param args command line args */ public static void main(String[] args) { - BlindingMagicWeapon blindingMagicWeapon = new BlindingMagicWeapon(new Excalibur()); - blindingMagicWeapon.wield(); - blindingMagicWeapon.blind(); - blindingMagicWeapon.swing(); - blindingMagicWeapon.unwield(); + LOGGER.info("The knight receives an enchanted sword."); + Sword enchantedSword = new Sword(new SoulEatingEnchantment()); + enchantedSword.wield(); + enchantedSword.swing(); + enchantedSword.unwield(); - FlyingMagicWeapon flyingMagicWeapon = new FlyingMagicWeapon(new Mjollnir()); - flyingMagicWeapon.wield(); - flyingMagicWeapon.fly(); - flyingMagicWeapon.swing(); - flyingMagicWeapon.unwield(); - - SoulEatingMagicWeapon soulEatingMagicWeapon = new SoulEatingMagicWeapon(new Stormbringer()); - soulEatingMagicWeapon.wield(); - soulEatingMagicWeapon.swing(); - soulEatingMagicWeapon.eatSoul(); - soulEatingMagicWeapon.unwield(); + LOGGER.info("The valkyrie receives an enchanted hammer."); + Hammer hammer = new Hammer(new FlyingEnchantment()); + hammer.wield(); + hammer.swing(); + hammer.unwield(); } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java deleted file mode 100644 index e70cbb96e..000000000 --- a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014-2016 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.bridge; - -/** - * - * BlindingMagicWeapon - * - */ -public class BlindingMagicWeapon extends MagicWeapon { - - public BlindingMagicWeapon(BlindingMagicWeaponImpl imp) { - super(imp); - } - - @Override - public BlindingMagicWeaponImpl getImp() { - return (BlindingMagicWeaponImpl) imp; - } - - @Override - public void wield() { - getImp().wieldImp(); - } - - @Override - public void swing() { - getImp().swingImp(); - } - - @Override - public void unwield() { - getImp().unwieldImp(); - } - - public void blind() { - getImp().blindImp(); - } -} diff --git a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/Enchantment.java similarity index 90% rename from bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImpl.java rename to bridge/src/main/java/com/iluwatar/bridge/Enchantment.java index c7b47e780..dd0c17205 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImpl.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Enchantment.java @@ -24,11 +24,14 @@ package com.iluwatar.bridge; /** * - * FlyingMagicWeaponImpl - * + * Enchantment + * */ -public abstract class FlyingMagicWeaponImpl extends MagicWeaponImpl { +public interface Enchantment { - public abstract void flyImp(); + void onActivate(); + void apply(); + + void onDeactivate(); } diff --git a/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java b/bridge/src/main/java/com/iluwatar/bridge/FlyingEnchantment.java similarity index 73% rename from bridge/src/main/java/com/iluwatar/bridge/Excalibur.java rename to bridge/src/main/java/com/iluwatar/bridge/FlyingEnchantment.java index ddd2ac540..8b12c6114 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java +++ b/bridge/src/main/java/com/iluwatar/bridge/FlyingEnchantment.java @@ -27,30 +27,25 @@ import org.slf4j.LoggerFactory; /** * - * Excalibur + * FlyingEnchantment * */ -public class Excalibur extends BlindingMagicWeaponImpl { +public class FlyingEnchantment implements Enchantment { - private static final Logger LOGGER = LoggerFactory.getLogger(Excalibur.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FlyingEnchantment.class); @Override - public void wieldImp() { - LOGGER.info("wielding Excalibur"); + public void onActivate() { + LOGGER.info("The item begins to glow faintly."); } @Override - public void swingImp() { - LOGGER.info("swinging Excalibur"); + public void apply() { + LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand."); } @Override - public void unwieldImp() { - LOGGER.info("unwielding Excalibur"); - } - - @Override - public void blindImp() { - LOGGER.info("bright light streams from Excalibur blinding the enemy"); + public void onDeactivate() { + LOGGER.info("The item's glow fades."); } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/Hammer.java similarity index 71% rename from bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeapon.java rename to bridge/src/main/java/com/iluwatar/bridge/Hammer.java index 85532d410..557ef6691 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeapon.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Hammer.java @@ -22,38 +22,39 @@ */ package com.iluwatar.bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * - * FlyingMagicWeapon + * Hammer * */ -public class FlyingMagicWeapon extends MagicWeapon { +public class Hammer implements Weapon { - public FlyingMagicWeapon(FlyingMagicWeaponImpl imp) { - super(imp); - } + private static final Logger LOGGER = LoggerFactory.getLogger(Hammer.class); - public FlyingMagicWeaponImpl getImp() { - return (FlyingMagicWeaponImpl) imp; + private final Enchantment enchantment; + + public Hammer(Enchantment enchantment) { + this.enchantment = enchantment; } @Override public void wield() { - getImp().wieldImp(); + LOGGER.info("The hammer is wielded."); + enchantment.onActivate(); } @Override public void swing() { - getImp().swingImp(); + LOGGER.info("The hammer is swinged."); + enchantment.apply(); } @Override public void unwield() { - getImp().unwieldImp(); + LOGGER.info("The hammer is unwielded."); + enchantment.onDeactivate(); } - - public void fly() { - getImp().flyImp(); - } - } diff --git a/bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java deleted file mode 100644 index 049133d91..000000000 --- a/bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014-2016 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.bridge; - -/** - * - * MagicWeapon - * - */ -public abstract class MagicWeapon { - - protected MagicWeaponImpl imp; - - public MagicWeapon(MagicWeaponImpl imp) { - this.imp = imp; - } - - public abstract void wield(); - - public abstract void swing(); - - public abstract void unwield(); - - public MagicWeaponImpl getImp() { - return imp; - } -} diff --git a/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImpl.java deleted file mode 100644 index b0d3070c1..000000000 --- a/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014-2016 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.bridge; - -/** - * - * MagicWeaponImpl - * - */ -public abstract class MagicWeaponImpl { - - public abstract void wieldImp(); - - public abstract void swingImp(); - - public abstract void unwieldImp(); - -} diff --git a/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java b/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java deleted file mode 100644 index 7cec530eb..000000000 --- a/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014-2016 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.bridge; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * Mjollnir - * - */ -public class Mjollnir extends FlyingMagicWeaponImpl { - - private static final Logger LOGGER = LoggerFactory.getLogger(Mjollnir.class); - - @Override - public void wieldImp() { - LOGGER.info("wielding Mjollnir"); - } - - @Override - public void swingImp() { - LOGGER.info("swinging Mjollnir"); - } - - @Override - public void unwieldImp() { - LOGGER.info("unwielding Mjollnir"); - } - - @Override - public void flyImp() { - LOGGER.info("Mjollnir hits the enemy in the air and returns back to the owner's hand"); - } -} diff --git a/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingEnchantment.java similarity index 76% rename from bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java rename to bridge/src/main/java/com/iluwatar/bridge/SoulEatingEnchantment.java index 0c7a6ce6b..8b08d155c 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java +++ b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingEnchantment.java @@ -27,30 +27,25 @@ import org.slf4j.LoggerFactory; /** * - * Stormbringer + * SoulEatingEnchantment * */ -public class Stormbringer extends SoulEatingMagicWeaponImpl { +public class SoulEatingEnchantment implements Enchantment { - private static final Logger LOGGER = LoggerFactory.getLogger(Stormbringer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SoulEatingEnchantment.class); @Override - public void wieldImp() { - LOGGER.info("wielding Stormbringer"); + public void onActivate() { + LOGGER.info("The item spreads bloodlust."); } @Override - public void swingImp() { - LOGGER.info("swinging Stormbringer"); + public void apply() { + LOGGER.info("The item eats the soul of enemies."); } @Override - public void unwieldImp() { - LOGGER.info("unwielding Stormbringer"); - } - - @Override - public void eatSoulImp() { - LOGGER.info("Stormbringer devours the enemy's soul"); + public void onDeactivate() { + LOGGER.info("Bloodlust slowly disappears."); } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImpl.java deleted file mode 100644 index 2ed27242a..000000000 --- a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014-2016 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.bridge; - -/** - * - * SoulEatingMagicWeaponImpl - * - */ -public abstract class SoulEatingMagicWeaponImpl extends MagicWeaponImpl { - - public abstract void eatSoulImp(); - -} diff --git a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/Sword.java similarity index 71% rename from bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeapon.java rename to bridge/src/main/java/com/iluwatar/bridge/Sword.java index 927ac2d66..73463b1f8 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeapon.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Sword.java @@ -22,39 +22,39 @@ */ package com.iluwatar.bridge; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * - * SoulEatingMagicWeapon + * Sword * */ -public class SoulEatingMagicWeapon extends MagicWeapon { +public class Sword implements Weapon { - public SoulEatingMagicWeapon(SoulEatingMagicWeaponImpl imp) { - super(imp); - } + private static final Logger LOGGER = LoggerFactory.getLogger(Sword.class); - @Override - public SoulEatingMagicWeaponImpl getImp() { - return (SoulEatingMagicWeaponImpl) imp; + private final Enchantment enchantment; + + public Sword(Enchantment enchantment) { + this.enchantment = enchantment; } @Override public void wield() { - getImp().wieldImp(); + LOGGER.info("The sword is wielded."); + enchantment.onActivate(); } @Override public void swing() { - getImp().swingImp(); + LOGGER.info("The sword is swinged."); + enchantment.apply(); } @Override public void unwield() { - getImp().unwieldImp(); + LOGGER.info("The sword is unwielded."); + enchantment.onDeactivate(); } - - public void eatSoul() { - getImp().eatSoulImp(); - } - } diff --git a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/Weapon.java similarity index 89% rename from bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImpl.java rename to bridge/src/main/java/com/iluwatar/bridge/Weapon.java index 0bd7d7b52..9bdd715a1 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImpl.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Weapon.java @@ -24,11 +24,14 @@ package com.iluwatar.bridge; /** * - * BlindingMagicWeaponImpl - * + * Weapon + * */ -public abstract class BlindingMagicWeaponImpl extends MagicWeaponImpl { +public interface Weapon { - public abstract void blindImp(); + void wield(); + void swing(); + + void unwield(); } diff --git a/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java index 97298a161..295641a10 100644 --- a/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java +++ b/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java @@ -42,14 +42,14 @@ public class BlindingMagicWeaponTest extends MagicWeaponTest { */ @Test public void testExcalibur() throws Exception { - final Excalibur excalibur = spy(new Excalibur()); - final BlindingMagicWeapon blindingMagicWeapon = new BlindingMagicWeapon(excalibur); - - testBasicWeaponActions(blindingMagicWeapon, excalibur); - - blindingMagicWeapon.blind(); - verify(excalibur, times(1)).blindImp(); - verifyNoMoreInteractions(excalibur); +// final Excalibur excalibur = spy(new Excalibur()); +// final Hammer blindingMagicWeapon = new Hammer(excalibur); +// +// testBasicWeaponActions(blindingMagicWeapon, excalibur); +// +// blindingMagicWeapon.blind(); +// verify(excalibur, times(1)).blindImp(); +// verifyNoMoreInteractions(excalibur); } } diff --git a/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java index fca3ea9ab..76bb77047 100644 --- a/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java +++ b/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java @@ -42,14 +42,14 @@ public class FlyingMagicWeaponTest extends MagicWeaponTest { */ @Test public void testMjollnir() throws Exception { - final Mjollnir mjollnir = spy(new Mjollnir()); - final FlyingMagicWeapon flyingMagicWeapon = new FlyingMagicWeapon(mjollnir); - - testBasicWeaponActions(flyingMagicWeapon, mjollnir); - - flyingMagicWeapon.fly(); - verify(mjollnir, times(1)).flyImp(); - verifyNoMoreInteractions(mjollnir); +// final Mjollnir mjollnir = spy(new Mjollnir()); +// final FlyingMagicWeapon flyingMagicWeapon = new FlyingMagicWeapon(mjollnir); +// +// testBasicWeaponActions(flyingMagicWeapon, mjollnir); +// +// flyingMagicWeapon.fly(); +// verify(mjollnir, times(1)).flyImp(); +// verifyNoMoreInteractions(mjollnir); } } \ No newline at end of file diff --git a/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java index e883f03d3..901880cc1 100644 --- a/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java +++ b/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java @@ -41,24 +41,24 @@ public abstract class MagicWeaponTest { * @param weaponImpl The spied weapon implementation where actions are bridged to * @param weapon The weapon, handled by the app */ - protected final void testBasicWeaponActions(final MagicWeapon weapon, - final MagicWeaponImpl weaponImpl) { - assertNotNull(weapon); - assertNotNull(weaponImpl); - assertNotNull(weapon.getImp()); - - weapon.swing(); - verify(weaponImpl, times(1)).swingImp(); - verifyNoMoreInteractions(weaponImpl); - - weapon.wield(); - verify(weaponImpl, times(1)).wieldImp(); - verifyNoMoreInteractions(weaponImpl); - - weapon.unwield(); - verify(weaponImpl, times(1)).unwieldImp(); - verifyNoMoreInteractions(weaponImpl); - + protected final void testBasicWeaponActions(final Weapon weapon, + final Enchantment weaponImpl) { +// assertNotNull(weapon); +// assertNotNull(weaponImpl); +// assertNotNull(weapon.getEnchantment()); +// +// weapon.swing(); +// verify(weaponImpl, times(1)).swingImp(); +// verifyNoMoreInteractions(weaponImpl); +// +// weapon.wield(); +// verify(weaponImpl, times(1)).wieldImp(); +// verifyNoMoreInteractions(weaponImpl); +// +// weapon.unwield(); +// verify(weaponImpl, times(1)).unwieldImp(); +// verifyNoMoreInteractions(weaponImpl); +// } } diff --git a/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java index b71fe2228..e3c5669ed 100644 --- a/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java +++ b/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java @@ -42,14 +42,14 @@ public class SoulEatingMagicWeaponTest extends MagicWeaponTest { */ @Test public void testStormBringer() throws Exception { - final Stormbringer stormbringer = spy(new Stormbringer()); - final SoulEatingMagicWeapon soulEatingMagicWeapon = new SoulEatingMagicWeapon(stormbringer); - - testBasicWeaponActions(soulEatingMagicWeapon, stormbringer); - - soulEatingMagicWeapon.eatSoul(); - verify(stormbringer, times(1)).eatSoulImp(); - verifyNoMoreInteractions(stormbringer); +// final Stormbringer stormbringer = spy(new Stormbringer()); +// final Sword soulEatingMagicWeapon = new Sword(stormbringer); +// +// testBasicWeaponActions(soulEatingMagicWeapon, stormbringer); +// +// soulEatingMagicWeapon.eatSoul(); +// verify(stormbringer, times(1)).eatSoulImp(); +// verifyNoMoreInteractions(stormbringer); } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 347a6bc15..06148064f 100644 --- a/pom.xml +++ b/pom.xml @@ -467,6 +467,7 @@ builder prototype adapter + bridge From 2a98a1399ec516cb3904d727384356f912e7f7e7 Mon Sep 17 00:00:00 2001 From: Gopinath Langote Date: Tue, 22 Aug 2017 14:21:05 +0530 Subject: [PATCH 345/492] #348 - Data Tranfer Object : Add Puml id to README.md. --- data-transfer-object/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/data-transfer-object/README.md b/data-transfer-object/README.md index ad9b9f4e2..7fe2d9cdc 100644 --- a/data-transfer-object/README.md +++ b/data-transfer-object/README.md @@ -3,6 +3,7 @@ layout: pattern title: Data Transfer Object folder: data-transfer-object permalink: /patterns/data-transfer-object/ +pumlid: RSh14SCW30NHLk82GFTq8uDYum71I5zn-t41kUtCswrfwL4bhBzEOFcRoFZEHyCPUxXOcGfHv387jHutWuqk_dAguktGj1WGKwV1_WJLvqWmLl-8fRbVKa22yXTosCWhHly1 categories: Architectural tags: - Java From 6f1736d2e6421241e3e15ba764c3e5303962b6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 22 Aug 2017 22:01:52 +0300 Subject: [PATCH 346/492] Refactored tests for Bridge --- .../main/java/com/iluwatar/bridge/Hammer.java | 5 ++ .../main/java/com/iluwatar/bridge/Sword.java | 5 ++ .../main/java/com/iluwatar/bridge/Weapon.java | 2 + ...ngMagicWeaponTest.java => HammerTest.java} | 22 ++------ .../bridge/SoulEatingMagicWeaponTest.java | 55 ------------------- ...ingMagicWeaponTest.java => SwordTest.java} | 24 +++----- .../{MagicWeaponTest.java => WeaponTest.java} | 47 +++++++--------- 7 files changed, 46 insertions(+), 114 deletions(-) rename bridge/src/test/java/com/iluwatar/bridge/{FlyingMagicWeaponTest.java => HammerTest.java} (69%) delete mode 100644 bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java rename bridge/src/test/java/com/iluwatar/bridge/{BlindingMagicWeaponTest.java => SwordTest.java} (69%) rename bridge/src/test/java/com/iluwatar/bridge/{MagicWeaponTest.java => WeaponTest.java} (65%) diff --git a/bridge/src/main/java/com/iluwatar/bridge/Hammer.java b/bridge/src/main/java/com/iluwatar/bridge/Hammer.java index 557ef6691..51bfda2a1 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Hammer.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Hammer.java @@ -57,4 +57,9 @@ public class Hammer implements Weapon { LOGGER.info("The hammer is unwielded."); enchantment.onDeactivate(); } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/Sword.java b/bridge/src/main/java/com/iluwatar/bridge/Sword.java index 73463b1f8..6f52943a6 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Sword.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Sword.java @@ -57,4 +57,9 @@ public class Sword implements Weapon { LOGGER.info("The sword is unwielded."); enchantment.onDeactivate(); } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } } diff --git a/bridge/src/main/java/com/iluwatar/bridge/Weapon.java b/bridge/src/main/java/com/iluwatar/bridge/Weapon.java index 9bdd715a1..a2d21b88f 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/Weapon.java +++ b/bridge/src/main/java/com/iluwatar/bridge/Weapon.java @@ -34,4 +34,6 @@ public interface Weapon { void swing(); void unwield(); + + Enchantment getEnchantment(); } diff --git a/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/HammerTest.java similarity index 69% rename from bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java rename to bridge/src/test/java/com/iluwatar/bridge/HammerTest.java index 76bb77047..a650bae04 100644 --- a/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java +++ b/bridge/src/test/java/com/iluwatar/bridge/HammerTest.java @@ -24,32 +24,22 @@ package com.iluwatar.bridge; import org.junit.Test; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.internal.verification.VerificationModeFactory.times; /** - * Date: 12/6/15 - 11:26 PM - * - * @author Jeroen Meulemeester + * Tests for hammer */ -public class FlyingMagicWeaponTest extends MagicWeaponTest { +public class HammerTest extends WeaponTest { /** * Invoke all possible actions on the weapon and check if the actions are executed on the actual * underlying weapon implementation. */ @Test - public void testMjollnir() throws Exception { -// final Mjollnir mjollnir = spy(new Mjollnir()); -// final FlyingMagicWeapon flyingMagicWeapon = new FlyingMagicWeapon(mjollnir); -// -// testBasicWeaponActions(flyingMagicWeapon, mjollnir); -// -// flyingMagicWeapon.fly(); -// verify(mjollnir, times(1)).flyImp(); -// verifyNoMoreInteractions(mjollnir); + public void testHammer() throws Exception { + final Hammer hammer = spy(new Hammer(mock(FlyingEnchantment.class))); + testBasicWeaponActions(hammer); } - } \ No newline at end of file diff --git a/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java deleted file mode 100644 index e3c5669ed..000000000 --- a/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014-2016 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.bridge; - -import org.junit.Test; - -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.internal.verification.VerificationModeFactory.times; - -/** - * Date: 12/6/15 - 11:43 PM - * - * @author Jeroen Meulemeester - */ -public class SoulEatingMagicWeaponTest extends MagicWeaponTest { - - /** - * Invoke all possible actions on the weapon and check if the actions are executed on the actual - * underlying weapon implementation. - */ - @Test - public void testStormBringer() throws Exception { -// final Stormbringer stormbringer = spy(new Stormbringer()); -// final Sword soulEatingMagicWeapon = new Sword(stormbringer); -// -// testBasicWeaponActions(soulEatingMagicWeapon, stormbringer); -// -// soulEatingMagicWeapon.eatSoul(); -// verify(stormbringer, times(1)).eatSoulImp(); -// verifyNoMoreInteractions(stormbringer); - } - -} \ No newline at end of file diff --git a/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/SwordTest.java similarity index 69% rename from bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java rename to bridge/src/test/java/com/iluwatar/bridge/SwordTest.java index 295641a10..7ffd0e492 100644 --- a/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java +++ b/bridge/src/test/java/com/iluwatar/bridge/SwordTest.java @@ -24,32 +24,22 @@ package com.iluwatar.bridge; import org.junit.Test; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.internal.verification.VerificationModeFactory.times; /** - * Date: 12/6/15 - 11:15 PM - * - * @author Jeroen Meulemeester + * Tests for sword */ -public class BlindingMagicWeaponTest extends MagicWeaponTest { +public class SwordTest extends WeaponTest { /** * Invoke all possible actions on the weapon and check if the actions are executed on the actual * underlying weapon implementation. */ @Test - public void testExcalibur() throws Exception { -// final Excalibur excalibur = spy(new Excalibur()); -// final Hammer blindingMagicWeapon = new Hammer(excalibur); -// -// testBasicWeaponActions(blindingMagicWeapon, excalibur); -// -// blindingMagicWeapon.blind(); -// verify(excalibur, times(1)).blindImp(); -// verifyNoMoreInteractions(excalibur); + public void testSword() throws Exception { + final Sword sword = spy(new Sword(mock(FlyingEnchantment.class))); + testBasicWeaponActions(sword); } - -} +} \ No newline at end of file diff --git a/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/WeaponTest.java similarity index 65% rename from bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java rename to bridge/src/test/java/com/iluwatar/bridge/WeaponTest.java index 901880cc1..daec1014a 100644 --- a/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java +++ b/bridge/src/test/java/com/iluwatar/bridge/WeaponTest.java @@ -28,37 +28,32 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.internal.verification.VerificationModeFactory.times; /** - * Date: 12/6/15 - 11:28 PM - * - * @author Jeroen Meulemeester + * Base class for weapon tests */ -public abstract class MagicWeaponTest { +public abstract class WeaponTest { /** - * Invoke the basic actions of the given weapon, and test if the underlying weapon implementation + * Invoke the basic actions of the given weapon, and test if the underlying enchantment implementation * is invoked * - * @param weaponImpl The spied weapon implementation where actions are bridged to - * @param weapon The weapon, handled by the app */ - protected final void testBasicWeaponActions(final Weapon weapon, - final Enchantment weaponImpl) { -// assertNotNull(weapon); -// assertNotNull(weaponImpl); -// assertNotNull(weapon.getEnchantment()); -// -// weapon.swing(); -// verify(weaponImpl, times(1)).swingImp(); -// verifyNoMoreInteractions(weaponImpl); -// -// weapon.wield(); -// verify(weaponImpl, times(1)).wieldImp(); -// verifyNoMoreInteractions(weaponImpl); -// -// weapon.unwield(); -// verify(weaponImpl, times(1)).unwieldImp(); -// verifyNoMoreInteractions(weaponImpl); -// - } + protected final void testBasicWeaponActions(final Weapon weapon) { + assertNotNull(weapon); + Enchantment enchantment = weapon.getEnchantment(); + assertNotNull(enchantment); + assertNotNull(weapon.getEnchantment()); + weapon.swing(); + verify(enchantment, times(1)).apply(); + verifyNoMoreInteractions(enchantment); + + weapon.wield(); + verify(enchantment, times(1)).onActivate(); + verifyNoMoreInteractions(enchantment); + + weapon.unwield(); + verify(enchantment, times(1)).onDeactivate(); + verifyNoMoreInteractions(enchantment); + + } } From 1dc038bc30798d849a127d5bbec62dffc32baebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 23 Aug 2017 21:25:48 +0300 Subject: [PATCH 347/492] Add explanation for Bridge pattern --- bridge/README.md | 166 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 3 deletions(-) diff --git a/bridge/README.md b/bridge/README.md index 6c1e70631..a37c35174 100644 --- a/bridge/README.md +++ b/bridge/README.md @@ -15,10 +15,170 @@ tags: Handle/Body ## Intent -Decouple an abstraction from its implementation so that the two can -vary independently. +Decouple an abstraction from its implementation so that the two can vary independently. -![alt text](./etc/bridge.png "Bridge") +## Explanation + +Real world example + +> Consider you have a weapon with different enchantments and you are supposed to allow mixing different weapons with different enchantments. What would you do? Create multiple copies of each of the weapons for each of the enchantments or would you just create separate enchantment and set it for the weapon as needed? Bridge pattern allows you to do the second. + +In Plain Words + +> Bridge pattern is about preferring composition over inheritance. Implementation details are pushed from a hierarchy to another object with a separate hierarchy. + +Wikipedia says + +> The bridge pattern is a design pattern used in software engineering that is meant to "decouple an abstraction from its implementation so that the two can vary independently" + +**Programmatic Example** + +Translating our weapon example from above. Here we have the `Weapon` hierarchy + +``` +public interface Weapon { + void wield(); + void swing(); + void unwield(); + Enchantment getEnchantment(); +} + +public class Sword implements Weapon { + + private final Enchantment enchantment; + + public Sword(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The sword is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The sword is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The sword is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} + +public class Hammer implements Weapon { + + private final Enchantment enchantment; + + public Hammer(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The hammer is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The hammer is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The hammer is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} +``` + +And the separate enchantment hierarchy + +``` +public interface Enchantment { + void onActivate(); + void apply(); + void onDeactivate(); +} + +public class FlyingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item begins to glow faintly."); + } + + @Override + public void apply() { + LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand."); + } + + @Override + public void onDeactivate() { + LOGGER.info("The item's glow fades."); + } +} + +public class SoulEatingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item spreads bloodlust."); + } + + @Override + public void apply() { + LOGGER.info("The item eats the soul of enemies."); + } + + @Override + public void onDeactivate() { + LOGGER.info("Bloodlust slowly disappears."); + } +} +``` + +And both the hierarchies in action + +``` +Sword enchantedSword = new Sword(new SoulEatingEnchantment()); +enchantedSword.wield(); +enchantedSword.swing(); +enchantedSword.unwield(); +// The sword is wielded. +// The item spreads bloodlust. +// The sword is swinged. +// The item eats the soul of enemies. +// The sword is unwielded. +// Bloodlust slowly disappears. + +Hammer hammer = new Hammer(new FlyingEnchantment()); +hammer.wield(); +hammer.swing(); +hammer.unwield(); +// The hammer is wielded. +// The item begins to glow faintly. +// The hammer is swinged. +// The item flies and strikes the enemies finally returning to owner's hand. +// The hammer is unwielded. +// The item's glow fades. +``` ## Applicability Use the Bridge pattern when From 08cc50e875f049d227610b8c7866249f3aa554f4 Mon Sep 17 00:00:00 2001 From: Chandan Rai Date: Thu, 31 Aug 2017 01:50:33 +0530 Subject: [PATCH 348/492] corrected typos --- balking/README.md | 2 +- event-queue/README.md | 4 ++-- feature-toggle/README.md | 2 +- layers/README.md | 2 +- promise/README.md | 4 ++-- prototype/README.md | 2 +- tls/README.md | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/balking/README.md b/balking/README.md index 1ca7ccfb1..f720c0d02 100644 --- a/balking/README.md +++ b/balking/README.md @@ -23,5 +23,5 @@ Use the Balking pattern when but for an unknown amount of time ## Related patterns -* Guarded Suspendion Pattern +* Guarded Suspension Pattern * Double Checked Locking Pattern \ No newline at end of file diff --git a/event-queue/README.md b/event-queue/README.md index 35fdac45c..081c01449 100644 --- a/event-queue/README.md +++ b/event-queue/README.md @@ -11,7 +11,7 @@ tags: --- ## Intent -Event Queue is a good pattern if You have a limited accesibility resource (for example: +Event Queue is a good pattern if You have a limited accessibility resource (for example: Audio or Database), but You need to handle all the requests that want to use that. It puts all the requests in a queue and process them asynchronously. Gives the resource for the event when it is the next in the queue and in same time @@ -22,7 +22,7 @@ removes it from the queue. ## Applicability Use the Event Queue pattern when -* You have a limited accesibility resource and the asynchronous process is acceptable to reach that +* You have a limited accessibility resource and the asynchronous process is acceptable to reach that ## Credits diff --git a/feature-toggle/README.md b/feature-toggle/README.md index 3bb91ad5a..06d956178 100644 --- a/feature-toggle/README.md +++ b/feature-toggle/README.md @@ -22,7 +22,7 @@ going to phase out is never removed, causing redundant code smells and increased ![alt text](./etc/feature-toggle.png "Feature Toggle") ## Applicability -Use the Feature Toogle pattern when +Use the Feature Toggle pattern when * Giving different features to different users. * Rolling out a new feature incrementally. diff --git a/layers/README.md b/layers/README.md index 8eac62412..62b562938 100644 --- a/layers/README.md +++ b/layers/README.md @@ -21,7 +21,7 @@ Layers is an architectural style where software responsibilities are ## Applicability Use the Layers architecture when -* you want clearly divide software responsibilities into differents parts of the program +* you want clearly divide software responsibilities into different parts of the program * you want to prevent a change from propagating throughout the application * you want to make your application more maintainable and testable diff --git a/promise/README.md b/promise/README.md index 65d463550..37fd214b7 100644 --- a/promise/README.md +++ b/promise/README.md @@ -27,7 +27,7 @@ in a synchronous way. Promise pattern is applicable in concurrent programming when some work needs to be done asynchronously and: -* code maintainablity and readability suffers due to callback hell. +* code maintainability and readability suffers due to callback hell. * you need to compose promises and need better error handling for asynchronous tasks. * you want to use functional style of programming. @@ -44,4 +44,4 @@ and: ## Credits * [You are missing the point to Promises](https://gist.github.com/domenic/3889970) -* [Functional style callbacks using CompleteableFuture](https://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture) +* [Functional style callbacks using CompletableFuture](https://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture) diff --git a/prototype/README.md b/prototype/README.md index e6d5d8b8b..477cd6e6f 100644 --- a/prototype/README.md +++ b/prototype/README.md @@ -36,7 +36,7 @@ In Java, it can be easily done by implementing `Cloneable` and overriding `clone ``` class Sheep implements Cloneable { - privage String name; + private String name; public Sheep(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return name; } diff --git a/tls/README.md b/tls/README.md index 02d889f50..3fb5e9a6b 100644 --- a/tls/README.md +++ b/tls/README.md @@ -19,4 +19,4 @@ Securing variables global to a thread against being spoiled by other threads. Th Use the Thread Local Storage in any of the following situations * when you use class variables in your Callable / Runnable object that are not read-only and you use the same Callable instance in more than one thread running in parallel. -* when you use static variables in your Callable / Runnable object that are not read-only and more than one instances of the Callable / Runnalbe may run in parallel threads. +* when you use static variables in your Callable / Runnable object that are not read-only and more than one instances of the Callable / Runnable may run in parallel threads. From f28ed7b46e5897f53efb20041e92f13a90fb9209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Thu, 31 Aug 2017 22:11:58 +0300 Subject: [PATCH 349/492] #590 Add explanation for Composite pattern --- composite/README.md | 114 +++++++++++++++++- composite/etc/composite.png | Bin 16195 -> 0 bytes composite/etc/composite.ucls | 75 ------------ composite/etc/composite.urm.puml | 43 ------- composite/etc/composite_1.png | Bin 33933 -> 0 bytes .../main/java/com/iluwatar/composite/App.java | 4 +- .../java/com/iluwatar/composite/Letter.java | 5 - .../iluwatar/composite/LetterComposite.java | 4 +- .../java/com/iluwatar/composite/Sentence.java | 5 - .../java/com/iluwatar/composite/Word.java | 5 - pom.xml | 1 + 11 files changed, 117 insertions(+), 139 deletions(-) delete mode 100644 composite/etc/composite.png delete mode 100644 composite/etc/composite.ucls delete mode 100644 composite/etc/composite.urm.puml delete mode 100644 composite/etc/composite_1.png diff --git a/composite/README.md b/composite/README.md index fce6ed6af..fbb21ecb3 100644 --- a/composite/README.md +++ b/composite/README.md @@ -16,7 +16,119 @@ Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. -![alt text](./etc/composite_1.png "Composite") +## Explanation + +Real world example + +> Every sentence is composed of words which are in turn composed of characters. Each of these objects is printable and they can have something printed before or after them like sentence always ends with full stop and word always has space before it + +In plain words + +> Composite pattern lets clients treat the individual objects in a uniform manner. + +Wikipedia says + +> In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly. + +**Programmatic Example** + +Taking our sentence example from above. Here we have the base class and different printable types + +``` +public abstract class LetterComposite { + private List children = new ArrayList<>(); + public void add(LetterComposite letter) { + children.add(letter); + } + public int count() { + return children.size(); + } + protected void printThisBefore() {} + protected void printThisAfter() {} + public void print() { + printThisBefore(); + for (LetterComposite letter : children) { + letter.print(); + } + printThisAfter(); + } +} + +public class Letter extends LetterComposite { + private char c; + public Letter(char c) { + this.c = c; + } + @Override + protected void printThisBefore() { + System.out.print(c); + } +} + +public class Word extends LetterComposite { + public Word(List letters) { + for (Letter l : letters) { + this.add(l); + } + } + @Override + protected void printThisBefore() { + System.out.print(" "); + } +} + +public class Sentence extends LetterComposite { + public Sentence(List words) { + for (Word w : words) { + this.add(w); + } + } + @Override + protected void printThisAfter() { + System.out.print("."); + } +} +``` + +Then we have a messenger to carry messages + +``` +public class Messenger { + LetterComposite messageFromOrcs() { + List words = new ArrayList<>(); + words.add(new Word(Arrays.asList(new Letter('W'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e')))); + words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e')))); + words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s')))); + words.add(new Word(Arrays.asList(new Letter('a')))); + words.add(new Word(Arrays.asList(new Letter('w'), new Letter('h'), new Letter('i'), new Letter('p')))); + words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e')))); + words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s')))); + words.add(new Word(Arrays.asList(new Letter('a')))); + words.add(new Word(Arrays.asList(new Letter('w'), new Letter('a'), new Letter('y')))); + return new Sentence(words); + } + + LetterComposite messageFromElves() { + List words = new ArrayList<>(); + words.add(new Word(Arrays.asList(new Letter('M'), new Letter('u'), new Letter('c'), new Letter('h')))); + words.add(new Word(Arrays.asList(new Letter('w'), new Letter('i'), new Letter('n'), new Letter('d')))); + words.add(new Word(Arrays.asList(new Letter('p'), new Letter('o'), new Letter('u'), new Letter('r'), new Letter('s')))); + words.add(new Word(Arrays.asList(new Letter('f'), new Letter('r'), new Letter('o'), new Letter('m')))); + words.add(new Word(Arrays.asList(new Letter('y'), new Letter('o'), new Letter('u'), new Letter('r')))); + words.add(new Word(Arrays.asList(new Letter('m'), new Letter('o'), new Letter('u'), new Letter('t'), new Letter('h')))); + return new Sentence(words); + } +} +``` + +And then it can be used as + +``` +LetterComposite orcMessage = new Messenger().messageFromOrcs(); +orcMessage.print(); // Where there is a whip there is a way. +LetterComposite elfMessage = new Messenger().messageFromElves(); +elfMessage.print(); // Much wind pours from your mouth. +``` ## Applicability Use the Composite pattern when diff --git a/composite/etc/composite.png b/composite/etc/composite.png deleted file mode 100644 index 1e6e6258ab696029a676688710bdcec0d95cbcc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16195 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 YN5E9DaLQOh19*g!hAN0xiy8+0KiLYo&Hw-a diff --git a/composite/etc/composite.ucls b/composite/etc/composite.ucls deleted file mode 100644 index 184c452f4..000000000 --- a/composite/etc/composite.ucls +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/composite/etc/composite.urm.puml b/composite/etc/composite.urm.puml deleted file mode 100644 index 82f2cab0d..000000000 --- a/composite/etc/composite.urm.puml +++ /dev/null @@ -1,43 +0,0 @@ -@startuml -package com.iluwatar.composite { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - class Letter { - - c : char - + Letter(c : char) - # printThisAfter() - # printThisBefore() - } - abstract class LetterComposite { - - children : List - + LetterComposite() - + add(letter : LetterComposite) - + count() : int - + print() - # printThisAfter() {abstract} - # printThisBefore() {abstract} - } - class Messenger { - + Messenger() - ~ messageFromElves() : LetterComposite - ~ messageFromOrcs() : LetterComposite - } - class Sentence { - + Sentence(words : List) - # printThisAfter() - # printThisBefore() - } - class Word { - + Word(letters : List) - # printThisAfter() - # printThisBefore() - } -} -LetterComposite --> "-children" LetterComposite -Letter --|> LetterComposite -Sentence --|> LetterComposite -Word --|> LetterComposite -@enduml \ No newline at end of file diff --git a/composite/etc/composite_1.png b/composite/etc/composite_1.png deleted file mode 100644 index 5f5b010dd2fbdfbcce43be338284ab69b1443f7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33933 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%0Aj|yv(XSrL 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 z5p;B_gg18)7!WIprototype adapter bridge + composite From a3324a122c5b5dd746dfa000a760d795b4659196 Mon Sep 17 00:00:00 2001 From: Dan Siwiec Date: Thu, 31 Aug 2017 18:28:27 -0700 Subject: [PATCH 350/492] Make toString synchronized. Closes #621 --- .../src/main/java/com/iluwatar/object/pool/ObjectPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java index df6e887b8..e76d00352 100644 --- a/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java +++ b/object-pool/src/main/java/com/iluwatar/object/pool/ObjectPool.java @@ -55,7 +55,7 @@ public abstract class ObjectPool { } @Override - public String toString() { + public synchronized String toString() { return String.format("Pool available=%d inUse=%d", available.size(), inUse.size()); } } From f439673de06cc6d0bc0a7e103a57a35af26e880f Mon Sep 17 00:00:00 2001 From: josejhgjghjghjghjghj <31527891+josejhgjghjghjghjghj@users.noreply.github.com> Date: Thu, 31 Aug 2017 22:58:50 -0400 Subject: [PATCH 351/492] Delete postPumlsToServer.firstrun.output --- _scripts/postPumlsToServer.firstrun.output | 190 --------------------- 1 file changed, 190 deletions(-) delete mode 100644 _scripts/postPumlsToServer.firstrun.output diff --git a/_scripts/postPumlsToServer.firstrun.output b/_scripts/postPumlsToServer.firstrun.output deleted file mode 100644 index ea77a49a5..000000000 --- a/_scripts/postPumlsToServer.firstrun.output +++ /dev/null @@ -1,190 +0,0 @@ -parent: half-sync-half-async; artifact: half-sync-half-async -Puml Server ID: RScv3SCm3030LU819FRPXg5fIm552tnYPFiyjRi3RkbAaYkdoQr5JBy369vrxz7oaSv6XmPhL3e6TCaJ0msU-CAoilTToyG8DdKOw5z0GzcAlvNAN_WZSD1brBHHPmxv0000 -parent: abstract-document; artifact: abstract-document -Puml Server ID: PSjB3eCm34NHhPG599vtDyQn85L-ifzX-p3lxEf8Twj3MXGDQvyJMFubChxpKN767gucSq07iinEjSNDOACVNvoAUZr6MWoe3QVE_WRnxZ0Mf38b-hkIGlurX_MyehS7 -parent: tolerant-reader; artifact: tolerant-reader -Puml Server ID: NSZ14SCm20NHLf829ExfXaYChGn26lZ4xSVdtFRjSrZJx9AkZnFOyI9olkenSEOxGxmjWnXgMvE6viLWfmz_kNI9SLZP38XRqEIuWx1Kd0t5XVjjGVj_DNtMdLD_ -parent: event-driven-architecture; artifact: event-driven-architecture -Puml Server ID: TOhH3SCW30LNQGS0_tSRnrZ15H1adfFromBzkfFktZQaHT7mzgh0N1yYvoUVXXf7B7Mv1dGWozN9MZmCTlhopQdeidEaoO3wMDHvRI6zzvwAssPYbsfGGRYIGlxN7DxpZDv- -parent: publish-subscribe; artifact: publish-subscribe -Puml Server ID: PSZB3SCm203GLTe1RExT1XCKKs5YyMdMR--zFRsd66aTNAwFcRdZ1U1uzrDorgXWfykIBJjT2qJhnaI7Dtwm7HnoMjkOoMu12-C7s3LKOhQe4UGo63ZfVtlvwhkMVW40 -parent: facade; artifact: facade -Puml Server ID: BSP15eCm20N0gxG7CEoz3ILKqvTW7dpq-hhehERTJ7fMJU-l7PYn4ZbVPMlOyvEXBeT13KMEGQtdnM2d7v-yL8sssJ8PKBUWmV64lYnSbHJoRqaVPUReDm00 -parent: service-locator; artifact: service-locator -Puml Server ID: NSjB3iCm203HgxG7iDdtDeIWX0fZYqzo_MRTtUX9ynOZhPtBzNLchlW0EDxza3nhgs2dQScMdUO0qRenqU6B5xQTGmvh2pFPBM1WF07FSmbnqqcOqu6J_gsNZxvgw0y0 -parent: dao; artifact: dao -Puml Server ID: 5SR14OKW30N0LhG0oVrt4o6ZE12Ov4NR_thQNQlc5aN2sd82qtz4naywAixOmyNoK8WYvT6fjdWOR7JnpLiHhuTkam4nTUhiRwZm847-J64zpUZj3m00 -parent: model-view-presenter; artifact: model-view-presenter -Puml Server ID: ROlR3SGW3C1MkGu0-RzjKeXQJWcWFChwPO3xispvQBrmL0hbp-q-xGkWkFBL_8upZBICxjGzbo7GE1OwAlpmmLJ9sjNJH7VIRY1e6q169KvFevMcakrtI_BoD-HGoJE4Nm00 -parent: observer; artifact: observer -Puml Server ID: FSkn4OGm30NHLg00hFow4KO3PcpP8tr1-pYwx6smQz5Suv2mkbp0y1-HyPlEWYlsSB7S5Q98kJSgDLu66ztyy7Q8brEtmO2OEZNs2Uhxl9u9GVv72cjfHAiV -parent: intercepting-filter; artifact: intercepting-filter -Puml Server ID: RSfB3i8m303Hgy014k-vZN5DQkIuaJ_q-fGzkz7JtCL8Q-DolUsPAnu0ZcSVadizAzZfi6JBJiS4qJenqU6D7smRXmnh2pFPBM1YN05o_KwyKcoqb-ZFEEcVz_BPLqtz0W00 -parent: factory-method; artifact: factory-method -Puml Server ID: NSZB3G8n30N0Lg20n7UwCOxPP9MVx6TMT0zdRgEvjoazYeRrMmMsFuYChtmqr7Y6gycQq8aiQr3hSJ7OwEGtfwBUZfas0shJQR3_G2yMBFkaeQYha4B-AeUDl6FqBm00 -parent: private-class-data; artifact: private-class-data -Puml Server ID: RShR3SCm243HLTe1RFwx3S4eeSB4uf6itmpGlwkZ-nOZhS7b-ZeoLtm07E--InwrLR3JQScMdSu9edLZeiCNBso3GtPh2pFPBM1YF07BvSBaHeeHRJm_SD8VxkMphvhw0m00 -parent: async-method-invocation; artifact: async-method-invocation -Puml Server ID: TSdB3SCW303GLTe1mFTkunWhk0A3_4dKxTi5UdlIUuhIoCPfuz4Zjhy03EzwIlGyqjbeQR16fJL1HjuOQF362qjZbrFBnWWsTPZeFm3wHwbCZhvQ4RqMOSXIuA1_LzDctJd75m00 -parent: execute-around; artifact: execute-around -Puml Server ID: NSZ14G8n20NGLhI0XBlT865suoGa0n_NylNixSsxTvEHJTF7xGHsF8YShtfqdFdCK9TbK4ELDQcFl1ZizE8tbwRH3okR0NKBcXm_a7vK4bhOLreZXVnLJPzrvnnV -parent: monostate; artifact: monostate -Puml Server ID: HSV14OGm20NGLjO23FVj1YEZsGaa0nzjVxrvUszfLdlkaju_9p3ZI-HybwFXp2r3l0w364eTIgtdpM2d7r-yxXBji7Ko86v1ol60TDW8C8G4zLr9rp9J-ny0 -parent: thread-pool; artifact: thread-pool -Puml Server ID: JSV14SCW30J0Lk82GFzq8uF6a1624IUx_UIPt-xHhMXK2TTN0zP-4pa_-UfeSSOMBzCWXbpceAxnCDZfmpUdAhjVbXO3uhPfyFw1q5oufZMdag3yFuUFl6Be5m00 -parent: delegation; artifact: delegation -Puml Server ID: JSV14GCX20NGLf82LkxfXbN69OFeu2VRVdBCxRsdUhLiac6F2rZxHHHybwwuyimjKQT37ANEGMfvCpZepHy-ccpjVYm697pJuFq3DJ7f39rEWlhNaZ7Aoc5V -parent: chain; artifact: chain -Puml Server ID: 9SR13SCm20NGLTe1OkxTXX0KKzd4Wa-pVYlrdTxJN4OTMZ4U7LZv8Wg-ssdejLTgoELGHvDhaesw6HpqvWzlXwQTlYq6D3nfSlv2qjcS5F9VgvXjrHnV -parent: resource-acquisition-is-initialization; artifact: resource-acquisition-is-initialization -Puml Server ID: ZShR3S8m343HLUW0YV_PnhXMQvGumOzMOdhA1lqxkhgBABLSEQqzzeZfJm33isuIUxxIsMXei4QbqK5QdXXeyCO3oyekcvQ94MpgqD4lWB6FDEA2z4bn2HbQn8leHMponNy13hgvrhHUP_Rs0m00 -parent: fluentinterface; artifact: fluentinterface -Puml Server ID: NOj93eCm302_KXv0VEzlN6F0bMCYB_3zvjpRQ3IpY97MnkNwEZD7l04SdtP8dlMfOAVBaYqRNHr4wy54Xo_Uk6uSSjWwC9FT0Zh61DYrPY_pyXs9WPF-NIllRLJN7m00 -parent: service-layer; artifact: service-layer -Puml Server ID: LOl93SCm3C1MQGUmzUysgY8aAcJ5q96WszVV_aW2V8gHriRb-ZWoPxm07E--Inxrhc2dqv8jEvq3HEl6H8SFNjWs3jcjJSnaju21iG3MSmbnK_mkuwJ_qij7dpNq1m00 -parent: visitor; artifact: visitor -Puml Server ID: DSR14OGm20NGLhG0mtsxmSWeJa8oyD7sTo_xJczLgoqFIM_B1Spu43c_vLHSkMU8rs4GGwcZaxPy6UnqyyFR8Q6dRPC1SGlg7B_Gew4OJeBwVqdlPMPlNm00 -parent: double-dispatch; artifact: double-dispatch -Puml Server ID: NSbB3iCW303HgpG70Ezx6yTOWSeOv4zp_MRTtUZDCPGa6wV9gqTiVmCOtlKQqVDCPwEbmHgLreGXUMEWmGU_M1hxkBHiZ61JXud-1BILft1fmvz37JZetshQh3kd_000 -parent: monad; artifact: monad -Puml Server ID: 9SR13SCm20NGLPe1OkxTXjWeSMMm1Pza_LRgExsjMntP97syBc35cyZvAMV7bKU6U9q6CPGwbVh8Xy5E7xvvRnBzj7qn86v1ol4BwJHk9AZ_bNGjAtLy0G00 -parent: front-controller; artifact: front-controller -Puml Server ID: PSlB3OGm303HLfO24j-t6nCC13bEvC_IFk6yjz6JPgbIE3OAvS_fFkmBe7Zde_ePQnXfwU8adajlK3bkT5Iuy8Tf8wk7f87kf6BGq6R0hlD8xwQTUG9v-SCSslA8nWy0 -parent: strategy; artifact: strategy -Puml Server ID: FSV13OCm30NGLM00udktCS4AGOaJsTz5tRwSkBstLiqj3WbhombC_n0PtwbKdB67Y-MX44NAerDjSJFOwE8lRuTuBRfD1iJKgRC_88SnfFn8aD-ai9vczFO7 -parent: command; artifact: command -Puml Server ID: DSgn4OCm30NGLM00h3xR25i7vYpXaxx2-g59zugtTgiZcwIFvGHcV8YSdt9qdBbdYDVR88PIRwK-yc6mqyLVtff4FsoR38XRa7Aye3SgMoD1_RkaQvcfumS0 -parent: abstract-factory; artifact: abstract-factory -Puml Server ID: PSZB3OD034NHLa81Czwd6sCC39gVxEUWT1_ssLmTtQLqgR5fM7sTmFGtaV6TZu8prd0r6HtQaMKqAZLk1XjT_E6qgPUZfyc0MdTgx0-8LuUn8ErFXdr98NypXxKyezKV -parent: flux; artifact: flux -Puml Server ID: 7SP14eCm20NGg-W13FlU1YFLE0GpyAazVZk-rPkRLSrDqdKwW14l8kUxx0r7hXdYzJA8eTIhKzEy6UnqyeUNJQBjjWm6n2seS_n3Ryql2UgJajxBoAu_ -parent: event-aggregator; artifact: event-aggregator -Puml Server ID: PSf13iCW30NHgxG70Ezx6uTOX0eCih-JwvTzTwEdUJSjFKu9wwyBMFuXCdvoRRZY21ShKo6ANEQWrkDXiD6NRqwdUAkQ5WDYwZJOTv3SUqzSgqbbp0qeVvZ3Hbun-Wy0 -parent: singleton; artifact: singleton -Puml Server ID: HSV14SCm20J0Lk82BFxf1ikCh0n26ZZizfDVVhjRjwfvIhg-Bc35cyZvAQtZoYD3l4w364gTWxhcms2d3z-ydnAzsRuO4BUWmV43HRUcWcaagF-Lz55M3lq2 -parent: null-object; artifact: null-object -Puml Server ID: JSV14SCm20J0Lk829Fxf1cF6bWSX3JhYzfDdVhjRSx4yDCDU5p3NcoZugMV3bNik3HaETLGPdPhbm-2WcpzS3btjz38PqF15dTSFv6bMndwhW1Jo_vhHwynkNm00 -parent: multiton; artifact: multiton -Puml Server ID: FST14i8m20NGg-W16lRUXgPCYnD81Zxs-hfozzvJlOywf68yBc3bYoZuRgVYghrIea-7E5gVHZhgPd3Gcp-y7P9w-hOOaF0au_o1h0OKqqdG_saLrbRP-080 -parent: composite; artifact: composite -Puml Server ID: HSf13eCm30NHgy01YFUzZGaM62LEP7-NwvTTT_EaMTLgoqFIst81Cpv4payv5LVk6U9r6CHGwkYaBHy6EztyvUsGqDEsoO2u1NMED-WTvmY5aA3-LT9xcTdR3m00 -parent: api-gateway; artifact: image-microservice -Puml Server ID: 3Sp13SCm2030LTe1RFxTXX3aK1biOOZLxPlVlUujHZrFJk-lAsAk3u3ZhatYoYCNEmqBjgWq5AJdna27BzvOJbxIh4oCOBS5Yki1u9JIC7ZZ3pW8HB5nKI4VJtSBSKtNEbFx7m00 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'api-gateway/etc/image-microservice.urm.puml' -pumlid: 3Sp13SCm2030LTe1RFxTXX3aK1biOOZLxPlVlUujHZrFJk-lAsAk3u3ZhatYoYCNEmqBjgWq5AJdna27BzvOJbxIh4oCOBS5Yki1u9JIC7ZZ3pW8HB5nKI4VJtSBSKtNEbFx7m00 -parent: api-gateway; artifact: api-gateway-service -Puml Server ID: JSox3SCm303HLP819FRUXg49cO542_nOyFPncUvUSszHwhbpMdyT4TCt0CDLcyIHdtGsEZLOez8vG7ek33JuueLbPvUcPM84cpeCz2S0fvI6mGjluA1_b-Tt2N5D6tNcw3y0 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'api-gateway/etc/api-gateway-service.urm.puml' -pumlid: JSox3SCm303HLP819FRUXg49cO542_nOyFPncUvUSszHwhbpMdyT4TCt0CDLcyIHdtGsEZLOez8vG7ek33JuueLbPvUcPM84cpeCz2S0fvI6mGjluA1_b-Tt2N5D6tNcw3y0 -parent: api-gateway; artifact: price-microservice -Puml Server ID: 3Sn13iGW243HgqmFeEpdDfGIoqJK8DJqzkFklyq_f56DYyFgvtOVymjWk78Hl-ECoKQzEJVFr1Mana97Wny-c2wUKbeQwCxM9YZE7O13Ka7dXI-m4mmJugH2rlVksSXXcaTe_GC0 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'api-gateway/etc/price-microservice.urm.puml' -pumlid: 3Sn13iGW243HgqmFeEpdDfGIoqJK8DJqzkFklyq_f56DYyFgvtOVymjWk78Hl-ECoKQzEJVFr1Mana97Wny-c2wUKbeQwCxM9YZE7O13Ka7dXI-m4mmJugH2rlVksSXXcaTe_GC0 -parent: object-pool; artifact: object-pool -Puml Server ID: JSV94SCm2030Lk829Fxf1cF6bWU1XYDkFtdcjxiD9Qc3o-LrPQvu0pW-_HnvrLx1JgR9cfrimf1wCD7XnW-sWsESsXPcicl0nFW1RB-PiYqp0KxwVo-VVTMKBm00 -parent: adapter; artifact: adapter -Puml Server ID: DSR14S8m30J0Lg20M7-wEMnDOiPMFDA9j0yyUEtUkzMHJTF7xI1NF4GSLzaxZtncgDVJgCPIpobzv0N2vOKtjgRHTziMI7KBcOXl10thfxB-Nz9dMJd71m00 -parent: hexagonal; artifact: hexagonal -Puml Server ID: HSTB4W8X30N0g-W1XkozpPD90LO8L3wEnzUTk-xxq2fvSfhSUiJs1v7XAcr4psSwMrqQh57gcZGaBmICNdZZEDb7qsCZWasT9lm7wln1MmeXZlfVIPjbvvGl -parent: value-object; artifact: value-object -Puml Server ID: LSZ13SCm20NGLTe1RExTXX2KECBOmfza_VRQszDxDnVBNJFiTG9pVOY2dteqdBdbqf3XK4ULqQbPFWmEklZcikjgXvV9W8Olwhn-e9ijjOpjKW4fv2zgHgypktq1 -parent: twin; artifact: twin -Puml Server ID: 7SR13OCm30NGLUW0n7UsCS42eyH4zdUpFbNVwNtKQij3qjjo0ICs8kTPJiMLUuPuVGnYAFNff2qdWvrk_l9wIEXfws10t88wno-4gKQ2-az9xsLaRoy0 -parent: semaphore; artifact: semaphore -Puml Server ID: HSV14SCm20J0Lk82BFxf1ikCfOn06ZZizfDVVhjRjphobFJnQi2ADv7pKwwEbaU6U9q6CPGwbVh8Xy5E7xvvFoNwPVjYGDo2bEC72b5URRgGeFvNqhMirF45 -parent: message-channel; artifact: message-channel -Puml Server ID: NSZB3SCm203GLTe1RExTXX1akm9YyMdMRy-zFRtdCf8wkLmUCtF72y3nxcFbhAE2dIvBjknqAIof6nCTtlZ1TdAiOMrZ9hi5ACOFe1o1WnjDD6C1Jlg_NgvzbyeN -parent: poison-pill; artifact: poison-pill -Puml Server ID: JSZ14SCm20NHLf82BExfXiYCJGOX3NpYzkDZRllsgTwjTgcmnmciV145N-rGdFMkbEZJ8OxMvo2rkXWSzE4lRxka7huj1YGyQN3UGMjgpdkh6Gdwlrl5QAk6_G00 -parent: aggregator-microservices; artifact: aggregator-service -Puml Server ID: JOov3SCm301NIGQGs7iRXYPa1g8ayB7NjuiKwGvtmBrbKC-Tq_hhY5Y-0HXUjKaS-Kbdepc2HrIQ2jBpma23BvvOTdPfeooCO1iEYlu0O6l63MDQKI6Rp-CKOWSE-ey_NzEqhjH-0m00 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'aggregator-microservices/etc/aggregator-service.urm.puml' -pumlid: JOov3SCm301NIGQGs7iRXYPa1g8ayB7NjuiKwGvtmBrbKC-Tq_hhY5Y-0HXUjKaS-Kbdepc2HrIQ2jBpma23BvvOTdPfeooCO1iEYlu0O6l63MDQKI6Rp-CKOWSE-ey_NzEqhjH-0m00 -parent: aggregator-microservices; artifact: information-microservice -Puml Server ID: LSnB3i8m303Hgy016k-vZN5DQXGxaJ_jzUcMtKXFcgSOZTgvV3oEp1Kl0CUhTScZtXNiD2tPij5Ka54N9ZfyySHjvv1ksy9CTWjGZ3i0UtVkcDCt5V9vFquX3k0a4FjCLqoPzgUjNDig7Jy0 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'aggregator-microservices/etc/information-microservice.urm.puml' -pumlid: LSnB3i8m303Hgy016k-vZN5DQXGxaJ_jzUcMtKXFcgSOZTgvV3oEp1Kl0CUhTScZtXNiD2tPij5Ka54N9ZfyySHjvv1ksy9CTWjGZ3i0UtVkcDCt5V9vFquX3k0a4FjCLqoPzgUjNDig7Jy0 -parent: aggregator-microservices; artifact: inventory-microservice -Puml Server ID: LSpB3G8n303HLg20ZUzqOxnMrYXn8d-oedjovJRIIEyfIYrFJckFAsBw2y3mBbNYodSw6mqDrYWqEaZB6mCDFhZmEDcbwZ4nWaqTEleEm5gDAyQmemlPsCOIOWSE0j6riM7VlrVIUfdPsmy0 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'aggregator-microservices/etc/inventory-microservice.urm.puml' -pumlid: LSpB3G8n303HLg20ZUzqOxnMrYXn8d-oedjovJRIIEyfIYrFJckFAsBw2y3mBbNYodSw6mqDrYWqEaZB6mCDFhZmEDcbwZ4nWaqTEleEm5gDAyQmemlPsCOIOWSE0j6riM7VlrVIUfdPsmy0 -parent: bridge; artifact: bridge -Puml Server ID: BSR14SCm20J0Lf82BFxf1akCJ4R26ZZYzkE7zxLljJgoIVfu7S2A3v7pLRhYo3r3l9u6CPHwJjAH5uETllpZhKbejsqn86v1a-CExQwj2mdgqv8-oyev_W00 -parent: servant; artifact: servant -Puml Server ID: DSkn4O0m20NGLNG0G-ys63cDbv0SV7HzRUnUy-QYkSOkONKwWU4haV6JZe8pjd2nt1MYIBatAZKU1XjTVFEoYvT3by60c3erzW_qdPiL9CY_KrXB8rfz0G00 -parent: lazy-loading; artifact: lazy-loading -Puml Server ID: LSXB3W8X303Gg-W1e7jlqu66gIc5zED4JwzRTo_lpjeaEwN9xOpO_W0mlEhWEFD89sjBWpHgMnDOyi90WoU-i7Ho7besHf2fmqJ_0GG_xo8BE-i0YlONDMtMdLE- -parent: flyweight; artifact: flyweight -Puml Server ID: HSV94S8m3030Lg20M7-w4OvYAoCh7Xtnq3ty-Eq-MQlaJcdow17JNm26gpIEdkzqidffa4Qfrm2MN1XeSEADsqxEJRU94MJgCD1_W4C-YxZr08hwNqaRPUQGBm00 -parent: mutex; artifact: mutex -Puml Server ID: 9SR13OCm30NGLSe0n7UsCS62LB69x6zWV2hrdTxKhFRS9Br_3c34GkHybxtXo3L3l9u6CPHwAhMUDuETldpnl4cqtUR1WBW5ASSlf0bvI53_A-bQHcf_0G00 -parent: mediator; artifact: mediator -Puml Server ID: FSV14SCm20J0Lk82BFxf1akCJKOW3JhizfDNVhkRUktP9AE_Bc2kDr7mKqx5bKSkYJeSuYXr66dFXy517xvvRxBqz7qo8E6BZDSFPDAKCO84zP-IOMMczIy0 -parent: page-object; artifact: page-object -Puml Server ID: JSV14OGW30NGLjO28FVj9iOCua1Wme-sxnxtzjvMJLeS6ju-9p3NbyZvoQNYZ3sMkWo36hACJhN5ms2dYszEXwvQB4q6r6rHv_K3JIwQndwfW1Jo_npUyupUNW00 -parent: factory-kit; artifact: factory-kit -Puml Server ID: JST15i8m20N0g-W14lRU1YcsQ4BooCS-RwzBTpDNSscvQKQx7C1SDwBWi-w68--vD6Gur55bTBAM9uE3dlpcikcotSjaGCCNTLu_q8C58pxbPI25_Bzcz3gpjoy0 -parent: property; artifact: property -Puml Server ID: FSV13OCm30NGLTe1YEziumOBKYMEPN-3s9wUUdlltRJst2Izlmx0OYLolihUSEGdGxnEXIXAdODQpul1Jby-UTaasgwBCI2kGOFZ1pAV9ewR1FMVaZwAvUWF -parent: dependency-injection; artifact: dependency-injection -Puml Server ID: RSdB3SCW303GLPe1mFTkunWhSGG6-PEesxS3zFQajubIpyPf_NL6B7y363xra3XpJsUZgS4QbUO0wVbWeC65DvR6BeUMXH5iwZ3GVu36YxMnqgU8NamXKu63_aPD6tNbw5y0 -parent: layers; artifact: layers -Puml Server ID: BSR13OCm30NGLSe0n7UsCS62L8w9x6yGszD3t-bDpQhc9kdwEO0H2v7pNVQ68zSCyNeQn53gsQbftWns-lB5yoRHTfi70-8Mr3b-8UL7F4XG_otflOpi-W80 -parent: producer-consumer; artifact: producer-consumer -Puml Server ID: PSjB3iCW303HgxG70Ezx6zTO2HKso9_a-c7VtUX9y-vA8nkdZTSPiVm3O7ZNeyUPttGscXgiKMaAz94t1XhyyCBIsFkXPM44cpe8-WvODbiIMzcdfspXe7-jQL9NodW0 -parent: builder; artifact: builder -Puml Server ID: DSR94O0m2030LhG0mzzkC64KXs26GzlNZw_TcRLADagJwOWOlW8OFcNdE79B9wkN1ccKUdLWoGS33KwySMdalEioC89C7Jhw5zYIfNrIrFybhPUHNLu0 -parent: specification; artifact: specification -Puml Server ID: LSX14i8m20NGg-W16lRU1YcsE0d9mCTUNxVkthoxkVJQjQBVJc3bWoZuQeVXh6UbXao7EfhCGTRhOd3Gcp-yxPfs-BOOqF2amVa3vLAnbmd3ffD2_gTLZBPgz2y0 -parent: state; artifact: state -Puml Server ID: 9SRH3O0m20N0LNG0ox_RO2LQqz867hg-9jxNpKLpZLt2wdG2mrSYuoST1MTiuMAvAqIHSczKQZmCDhhuvcKNBuSkWm4nTMhiNyZ141BaVocifH6jlW00 -parent: reader-writer-lock; artifact: reader-writer-lock -Puml Server ID: RSZB4S8m303HLg00MtUw4R8cCP5bZpwuVL80jttxx4gIZTFaSKOiVm4OxdhqEFETpaPJWpKgpG5TScEWmGU_M1fxFxGiZ61JXu5-1nXZOolR-gqYaoxWe3-xfeswSiWF -parent: interpreter; artifact: interpreter -Puml Server ID: JSf13eCm30NHgz034E-vZGaM62Kcih_BzQ6xxjv8yr6hBJT9RzC1Z5Y8dE-oAuvSCyJhPH13gLSdRNapsEdaBy-RXEus3mR4BQXpl21zVnykFmlgVvVqNaRszW00 -parent: template-method; artifact: template-method -Puml Server ID: NSZ13SCW30NGLPe1mFTkuu0Lg6n0vZjPlpttzlIEFef6bN1zDM3jDv7paw-E5cTiyJ87P22NQTGr7WOxVVZcL6NtQwJ5WFZOPBn_88WjPKWoGPkL1EN_ShZb5QPV -parent: feature-toggle; artifact: feature-toggle -Puml Server ID: NSZ14G8X30NGLhG0oDrk8XjPd12OvCTjNy_UthpxiAPvIBhUJc37WyZvgdtWp6U6U5i6CTIs9WtDYy5ER_vmEIH6jx8P4BUWoV43lOIHBWMhTnKIjB-gwRFkdFe5 -parent: business-delegate; artifact: business-delegate -Puml Server ID: POl13SCm3CHMQGU8zUysgYCuBcJ5a4x9-l6_Fu84tzsgvYxf-Zg06HyYvxkqZYE_6UBrD8YXr7DGrxmPxFJZYxTTeZVR9WFY5ZGu5j2wkad4wYgD8IIe_xQaZp9pw0C0 -parent: naked-objects; artifact: naked-objects-integtests -Puml Server ID: LSmn4iCW30NHgoG70FMvZGmQ6ni48tt5ru_RT3kls7VJqgDAM7yTmF8FaV6TzuOZjd2nCXMYo6KEQZrk1XkT_ELKnTkkQJ4Wfaw3_GbIlgIckPrIu2Ge_vBQyziX3izX8wyO_GS0 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'naked-objects/etc/naked-objects-integtests.urm.puml' -pumlid: LSmn4iCW30NHgoG70FMvZGmQ6ni48tt5ru_RT3kls7VJqgDAM7yTmF8FaV6TzuOZjd2nCXMYo6KEQZrk1XkT_ELKnTkkQJ4Wfaw3_GbIlgIckPrIu2Ge_vBQyziX3izX8wyO_GS0 -parent: naked-objects; artifact: naked-objects-dom -Puml Server ID: LSZ94SCW3030Lf82G7zt8mkDZOC4eyDkF_dcjxFlhZIoSTfudH7BDm33fnuzpjpJsMXgi4QbAT17FXXeSE6DfR7tGyl223Pr4FGVGF73hSpzOWe73lgVqgRKDAahPNm1 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'naked-objects/etc/naked-objects-dom.urm.puml' -pumlid: LSZ94SCW3030Lf82G7zt8mkDZOC4eyDkF_dcjxFlhZIoSTfudH7BDm33fnuzpjpJsMXgi4QbAT17FXXeSE6DfR7tGyl223Pr4FGVGF73hSpzOWe73lgVqgRKDAahPNm1 -parent: naked-objects; artifact: naked-objects-fixture -Puml Server ID: LSX15i8W30N0g-W187jlaq9igH1uoO_r-BfrDs_kJKkFAc7zTW3B7qJ6LzuRZjZ2nSfKY2ANEQZrk1XiTFARKnLlkwR5W9Ww3VOVIFabDStjb08dGVcVz6mVX4aE6td5w5y0 -I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file 'naked-objects/etc/naked-objects-fixture.urm.puml' -pumlid: LSX15i8W30N0g-W187jlaq9igH1uoO_r-BfrDs_kJKkFAc7zTW3B7qJ6LzuRZjZ2nSfKY2ANEQZrk1XiTFARKnLlkwR5W9Ww3VOVIFabDStjb08dGVcVz6mVX4aE6td5w5y0 -parent: model-view-controller; artifact: model-view-controller -Puml Server ID: ROl13SCm201NQGUm-NSRQgE42h258Lw_wR-_qvtkoTOaEwNBuuoOwmNWkEl1SUOx5taR5cHHsr1WoOs13X-yi7HQV5YP645k2nJN3Q2ZavIBQPVVwqFajXJjVwdfMcUgV040 -parent: proxy; artifact: proxy -Puml Server ID: 9SR13OCm30NGLM00udktCS62eCI9x6yesrEfx_Jcehd69c5rEe3X7oBZE-q5HwpXOhahH95oRrHgt0msEldYPHClkow30J5rQko_qB3-VKYG_qjXBOrezGK0 -parent: memento; artifact: memento -Puml Server ID: DSgn4OCm30NGLM00h3xR2AC3SvRiaxx2-g59zugtDgiz3qdlomNC-10vF-Lik7BF4A_388PIXrBh-J3OwUOlRuT4EssR38XRa7Ay81Lz_o11_RkaQvcf_GS0 -parent: decorator; artifact: decorator -Puml Server ID: HSV14SCm20J0Lk82BFxf1YF6LaP26ZZizfDVVhjRC-bPDRs_Bc35cyZvAMV3bKU6kao36ehCGQtdms2d3z-yLursshuOKBUWmV43LPNfZEcaaFzA-YWhH_y2 -parent: data-mapper; artifact: data-mapper -Puml Server ID: JShB3OGm303HLg20nFVjnYGM1CN6ycTfVtFSsnjfzY5jPgUqkLqHwXy0mxUU8wuyqidQ8q4IjJqCO-QBWGOtVh5qyd5AKOmW4mT6Nu2-ZiAekapH_hkcSTNa-GC0 -parent: caching; artifact: caching -Puml Server ID: DSRB4OKm2030LhG0m_rrWyWaE0bc-6ZxpujxsbMKUXwSrfSMCVq7OFYKAj5oJsUZIuCr2bq3fEU3WGOdthWTx59rcnZ1fWu3_GqGKXEjm47VIzeeCqV_0m00 -parent: reactor; artifact: reactor -Puml Server ID: DSR14OGm20NGLjO23FVj1f7Hx2Ga0nzjVxtuJc-f9YrtJM-V4vZn9NA-or5nvfQXBiEWXYAZKsrvCzZfnnUlkqOzR9qCg5jGvtX2hYmOJWfvNz9xcTdR7m00 -parent: iterator; artifact: iterator -Puml Server ID: FSV13OGm30NHLg00uljsOu85HeaJsTzB-yjfBwCtgrfjUKXwMovWneV8-IcduiezGxmEWnXA7PsqvSDWfvk_l1qIUjes6H2teCxnWlGDOpW9wdzAUYypU_i1 -parent: callback; artifact: callback -Puml Server ID: FSVB4S8m30N0Lg20M7UwUL4qYOciUFGXxSE9s-wp6sjjKgwF8tF6YyXnjxtdKMk5E5-MOjdu6jIrRYIStlXWsIJwRij4fhW53SGFn51TmIT9yZ-jVBHPGxy0 -parent: repository; artifact: repository -Puml Server ID: JSV13OCm30NGLM00udktCS42eyI9xE-YRjyUUtjlLQij3qblomNCU14vF-LKNBbdYDTX44EfevEsV1ZiTFERjqD2Jzic0-8Mr3b-89SvGZ7yGuBwrvBUoypUlW00 -parent: mute-idiom; artifact: mute-idiom -Puml Server ID: JSf13iCm20NHgxG7iDdtDjH62PKX5luarq-MtSsJvgtUHdR96AyTcEj357pLJR7dDvT4EnpYgEqmqf4NWuD-V7BfidJpCXcGy4N6wmcoX1Jj-lo2ziUQONMcZHi0 -parent: prototype; artifact: prototype -Puml Server ID: HSV13OCm30NGLM00udktCS62eCInxE-YRj_UUdjlRLfx7fBUbmkmU14vF-Lik7BF4AzJ8OfIvw3Mys6mqyrltWw9Tkfc38XhqE3uWSmd9Zuc9AZ_bVHHB4V_0W00 -parent: step-builder; artifact: step-builder -Puml Server ID: LOZ93SCm3C1MQGQmzUysYYqaAcJ5q96i7t_x8KXkh4soKvfypeZfNm33fnuSP-xfPEtI88tQhW4i-M2WmGzlB9sS3oqJ8yZKOQ0lWOLPzcJfAoZQtwXfeyuSyW80 -parent: double-checked-locking; artifact: double-checked-locking -Puml Server ID: TSdH4SCW203GLTe1bFzkGv1J6qGFeLc_MI1_x-wzkv94uJ1vDVUrFm26LwxTMnonsMYgitgcEQ1BNEXeyCKVfiAxLqqBtTbqmy1z0ygCGpXHOpgv99bqTgt0JW-LmqPUCUGF From c6354c48bb0f62c3030d63a824812173263adac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20Hamzao=C4=9Fullar=C4=B1?= Date: Sat, 2 Sep 2017 21:52:02 +0300 Subject: [PATCH 352/492] - removed optional classes and interfaces in order to simplify the example - final fields are marked as final - removed unnecessary temp variables - added private constructor for not instantiated static class AccountAggregate - path of te test file is corrected --- event-sourcing/etc/event-sourcing.png | Bin 105812 -> 60339 bytes event-sourcing/etc/event-sourcing.ucls | 252 ++++-------------- .../event/sourcing/AccountService.java | 56 ---- .../sourcing/MoneyTransactionService.java | 85 ------ .../event/sourcing/SequenceIdGenerator.java | 42 --- .../event/sourcing/api/EventProcessor.java | 48 ---- .../event/sourcing/api/ProcessorJournal.java | 48 ---- .../com/iluwatar/event/sourcing/app/App.java | 50 ++-- .../event/sourcing/domain/Account.java | 71 ++--- .../event/sourcing/domain/Transaction.java | 98 ------- .../sourcing/event/AccountCreateEvent.java | 6 +- .../sourcing/{api => event}/DomainEvent.java | 4 +- .../sourcing/event/MoneyDepositEvent.java | 10 +- .../sourcing/event/MoneyTransferEvent.java | 16 +- .../sourcing/event/MoneyWithdrawalEvent.java | 78 ------ .../gateway/AccountCreateContractSender.java | 40 --- .../event/sourcing/gateway/Gateways.java | 50 ---- .../sourcing/gateway/TransactionLogger.java | 40 --- .../processor/DomainEventProcessor.java | 34 ++- .../JsonFileJournal.java | 42 +-- .../sourcing/state/AccountAggregate.java | 8 +- .../java}/IntegrationTest.java | 60 ++--- 22 files changed, 207 insertions(+), 931 deletions(-) delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/AccountService.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/MoneyTransactionService.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/SequenceIdGenerator.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/EventProcessor.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/ProcessorJournal.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java rename event-sourcing/src/main/java/com/iluwatar/event/sourcing/{api => event}/DomainEvent.java (95%) delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java delete mode 100644 event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java rename event-sourcing/src/main/java/com/iluwatar/event/sourcing/{journal => processor}/JsonFileJournal.java (84%) rename event-sourcing/src/{main/test/java/com/iluwatar/event/sourcing => test/java}/IntegrationTest.java (59%) diff --git a/event-sourcing/etc/event-sourcing.png b/event-sourcing/etc/event-sourcing.png index ac7192b195fb67b1d67c1b5c0e5fcc3a5cfd6fb0..0b0098546300e34203b06fefec325f0a81e1d1f7 100644 GIT binary patch literal 60339 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%0AKM&}B6&mY86G=qr~XfB};B`_tT#9i`_L z(7Xc6%eqv&?UHtT7iV7XC1!((wai=i6$b<4Q3FJ>vTjL-Bj4cLq@nn>LEWV)9ax`V z-Er*nKWp&$pM9$&8qQDctbcFka#8!o;y5YmGBB4h_Q2|uFH~F8=|f+(g08ISj=v~( z5yxSO4lME1UO}Y2!)NQ2;^T0(jWC7lun(Be(dr}0CZMAgZQAz{14fouYq{@OmE*)5 z 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 literal 105812 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 M|6O9HyGJ!3|Bxmyy?LP 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 diff --git a/event-sourcing/etc/event-sourcing.ucls b/event-sourcing/etc/event-sourcing.ucls index e6944ef70..2df56a479 100644 --- a/event-sourcing/etc/event-sourcing.ucls +++ b/event-sourcing/etc/event-sourcing.ucls @@ -1,50 +1,50 @@ - - - + - - - - - - - - - - - - - - - - + - - + + + + + + + + + + + + + + + @@ -55,203 +55,63 @@ project="event-sourcing" file="/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java" binary="false" corner="BOTTOM_RIGHT"> - + - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - - - - - - - - - + - - + + + + + + - + - - - - - - - - - - + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + transactions; /** * Instantiates a new Account. @@ -52,7 +55,6 @@ public class Account { this.accountNo = accountNo; this.owner = owner; money = BigDecimal.ZERO; - transactions = new ArrayList<>(); } /** @@ -91,23 +93,6 @@ public class Account { this.money = money; } - /** - * Gets transactions. - * - * @return the transactions - */ - public List getTransactions() { - return transactions; - } - - /** - * Sets transactions. - * - * @param transactions the transactions - */ - public void setTransactions(List transactions) { - this.transactions = transactions; - } /** * Copy account. @@ -117,7 +102,6 @@ public class Account { public Account copy() { Account account = new Account(accountNo, owner); account.setMoney(money); - account.setTransactions(transactions); return account; } @@ -127,29 +111,22 @@ public class Account { + "accountNo=" + accountNo + ", owner='" + owner + '\'' + ", money=" + money - + ", transactions=" + transactions + '}'; } - private Transaction depositMoney(BigDecimal money) { + private void depositMoney(BigDecimal money) { this.money = this.money.add(money); - Transaction transaction = new Transaction(accountNo, money, BigDecimal.ZERO, this.money); - transactions.add(transaction); - return transaction; } - private Transaction withdrawMoney(BigDecimal money) { + private void withdrawMoney(BigDecimal money) { this.money = this.money.subtract(money); - Transaction transaction = new Transaction(accountNo, BigDecimal.ZERO, money, this.money); - transactions.add(transaction); - return transaction; } private void handleDeposit(BigDecimal money, boolean realTime) { - Transaction transaction = depositMoney(money); + depositMoney(money); AccountAggregate.putAccount(this); if (realTime) { - Gateways.getTransactionLogger().log(transaction); + LOGGER.info("Some external api for only realtime execution could be called here."); } } @@ -158,15 +135,15 @@ public class Account { throw new RuntimeException("Insufficient Account Balance"); } - Transaction transaction = withdrawMoney(money); + withdrawMoney(money); AccountAggregate.putAccount(this); if (realTime) { - Gateways.getTransactionLogger().log(transaction); + LOGGER.info("Some external api for only realtime execution could be called here."); } } /** - * Handle event. + * Handles the MoneyDepositEvent. * * @param moneyDepositEvent the money deposit event */ @@ -176,29 +153,19 @@ public class Account { /** - * Handle event. - * - * @param moneyWithdrawalEvent the money withdrawal event - */ - public void handleEvent(MoneyWithdrawalEvent moneyWithdrawalEvent) { - handleWithdrawal(moneyWithdrawalEvent.getMoney(), moneyWithdrawalEvent.isRealTime()); - } - - /** - * Handle event. + * Handles the AccountCreateEvent. * * @param accountCreateEvent the account create event */ public void handleEvent(AccountCreateEvent accountCreateEvent) { AccountAggregate.putAccount(this); - // check if this event is replicated from journal before calling an external gateway function if (accountCreateEvent.isRealTime()) { - Gateways.getAccountCreateContractSender().sendContractInfo(this); + LOGGER.info("Some external api for only realtime execution could be called here."); } } /** - * Handle transfer from event. + * Handles transfer from account event. * * @param moneyTransferEvent the money transfer event */ @@ -207,7 +174,7 @@ public class Account { } /** - * Handle transfer to event. + * Handles transfer to account event. * * @param moneyTransferEvent the money transfer event */ diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java deleted file mode 100644 index a0d921f5f..000000000 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/domain/Transaction.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.event.sourcing.domain; - -import java.math.BigDecimal; - -/** - * Created by Serdar Hamzaogullari on 06.08.2017. - */ -public class Transaction { - - private final int accountNo; - private final BigDecimal moneyIn; - private final BigDecimal moneyOut; - private final BigDecimal lastBalance; - - /** - * Instantiates a new Transaction. - * - * @param accountNo the account no - * @param moneyIn the money in - * @param moneyOut the money out - * @param lastBalance the last balance - */ - public Transaction(int accountNo, BigDecimal moneyIn, BigDecimal moneyOut, - BigDecimal lastBalance) { - this.accountNo = accountNo; - this.moneyIn = moneyIn; - this.moneyOut = moneyOut; - this.lastBalance = lastBalance; - } - - /** - * Gets account no. - * - * @return the account no - */ - public int getAccountNo() { - return accountNo; - } - - /** - * Gets money in. - * - * @return the money in - */ - public BigDecimal getMoneyIn() { - return moneyIn; - } - - /** - * Gets money out. - * - * @return the money out - */ - public BigDecimal getMoneyOut() { - return moneyOut; - } - - /** - * Gets last balance. - * - * @return the last balance - */ - public BigDecimal getLastBalance() { - return lastBalance; - } - - @Override - public String toString() { - return "Transaction{" - + "accountNo=" + accountNo - + ", moneyIn=" + moneyIn - + ", moneyOut=" + moneyOut - + ", lastBalance=" + lastBalance - + '}'; - } -} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java index 350104267..c526396f3 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/AccountCreateEvent.java @@ -22,11 +22,15 @@ */ package com.iluwatar.event.sourcing.event; -import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; import com.iluwatar.event.sourcing.state.AccountAggregate; /** + * This is the class that implements account create event. + * Holds the necessary info for an account create event. + * Implements the process function that finds the event related + * domain objects and calls the related domain object's handle event functions + * * Created by Serdar Hamzaogullari on 06.08.2017. */ public class AccountCreateEvent extends DomainEvent { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/DomainEvent.java similarity index 95% rename from event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java rename to event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/DomainEvent.java index 6eb5141a2..fa6539a4f 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/api/DomainEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/DomainEvent.java @@ -20,11 +20,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.event.sourcing.api; +package com.iluwatar.event.sourcing.event; import java.io.Serializable; /** + * This is the base class for domain events. All events must extend this class. + * * Created by Serdar Hamzaogullari on 06.08.2017. */ public abstract class DomainEvent implements Serializable { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java index 3fb61bd08..1629263a7 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyDepositEvent.java @@ -22,18 +22,22 @@ */ package com.iluwatar.event.sourcing.event; -import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; /** + * This is the class that implements money deposit event. + * Holds the necessary info for a money deposit event. + * Implements the process function that finds the event related + * domain objects and calls the related domain object's handle event functions + * * Created by Serdar Hamzaogullari on 06.08.2017. */ public class MoneyDepositEvent extends DomainEvent { - private BigDecimal money; - private int accountNo; + private final BigDecimal money; + private final int accountNo; /** * Instantiates a new Money deposit event. diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java index bbba89988..0307d3af7 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyTransferEvent.java @@ -22,19 +22,23 @@ */ package com.iluwatar.event.sourcing.event; -import com.iluwatar.event.sourcing.api.DomainEvent; import com.iluwatar.event.sourcing.domain.Account; import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; /** + * This is the class that implements money transfer event. + * Holds the necessary info for a money transfer event. + * Implements the process function that finds the event related + * domain objects and calls the related domain object's handle event functions + * * Created by Serdar Hamzaogullari on 06.08.2017. */ public class MoneyTransferEvent extends DomainEvent { - private BigDecimal money; - private int accountNoFrom; - private int accountNoTo; + private final BigDecimal money; + private final int accountNoFrom; + private final int accountNoTo; /** * Instantiates a new Money transfer event. @@ -63,7 +67,7 @@ public class MoneyTransferEvent extends DomainEvent { } /** - * Gets account no from. + * Gets account no which the money comes from. * * @return the account no from */ @@ -72,7 +76,7 @@ public class MoneyTransferEvent extends DomainEvent { } /** - * Gets account no to. + * Gets account no which the money goes to. * * @return the account no to */ diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java deleted file mode 100644 index d8c295002..000000000 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/event/MoneyWithdrawalEvent.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.event.sourcing.event; - -import com.iluwatar.event.sourcing.api.DomainEvent; -import com.iluwatar.event.sourcing.domain.Account; -import com.iluwatar.event.sourcing.state.AccountAggregate; -import java.math.BigDecimal; - -/** - * Created by Serdar Hamzaogullari on 06.08.2017. - */ -public class MoneyWithdrawalEvent extends DomainEvent { - - private BigDecimal money; - private int accountNo; - - /** - * Instantiates a new Money withdrawal event. - * - * @param sequenceId the sequence id - * @param createdTime the created time - * @param accountNo the account no - * @param money the money - */ - public MoneyWithdrawalEvent(long sequenceId, long createdTime, int accountNo, BigDecimal money) { - super(sequenceId, createdTime, "MoneyWithdrawalEvent"); - this.money = money; - this.accountNo = accountNo; - } - - /** - * Gets money. - * - * @return the money - */ - public BigDecimal getMoney() { - return money; - } - - /** - * Gets account no. - * - * @return the account no - */ - public int getAccountNo() { - return accountNo; - } - - @Override - public void process() { - Account account = AccountAggregate.getAccount(accountNo); - if (account == null) { - throw new RuntimeException("Account not found"); - } - account.handleEvent(this); - } -} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java deleted file mode 100644 index baaf41f56..000000000 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/AccountCreateContractSender.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.event.sourcing.gateway; - -import com.iluwatar.event.sourcing.domain.Account; - -/** - * Created by Serdar Hamzaogullari on 06.08.2017. - */ -public class AccountCreateContractSender { - - /** - * Send contract info. - * - * @param account the account - */ - public void sendContractInfo(Account account) { - // an example imaginary funciton which sends account info to some external end point - } -} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java deleted file mode 100644 index 84bdff3b2..000000000 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/Gateways.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.event.sourcing.gateway; - -/** - * Created by Serdar Hamzaogullari on 06.08.2017. - */ -public class Gateways { - - private static AccountCreateContractSender accountCreateContractSender = new AccountCreateContractSender(); - private static TransactionLogger transactionLogger = new TransactionLogger(); - - /** - * Gets account create contract sender. - * - * @return the account create contract sender - */ - public static AccountCreateContractSender getAccountCreateContractSender() { - return accountCreateContractSender; - } - - /** - * Gets transaction logger. - * - * @return the transaction logger - */ - public static TransactionLogger getTransactionLogger() { - return transactionLogger; - } -} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java deleted file mode 100644 index 42ae7a1f5..000000000 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/gateway/TransactionLogger.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014 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.event.sourcing.gateway; - -import com.iluwatar.event.sourcing.domain.Transaction; - -/** - * Created by Serdar Hamzaogullari on 06.08.2017. - */ -public class TransactionLogger { - - /** - * Log. - * - * @param transaction the transaction - */ - public void log(Transaction transaction) { - // example imaginary function that logs the transaction to somewhere - } -} diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java index 38e72995d..05308c7c1 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/DomainEventProcessor.java @@ -22,33 +22,43 @@ */ package com.iluwatar.event.sourcing.processor; -import com.iluwatar.event.sourcing.api.DomainEvent; -import com.iluwatar.event.sourcing.api.EventProcessor; -import com.iluwatar.event.sourcing.api.ProcessorJournal; +import com.iluwatar.event.sourcing.event.DomainEvent; /** + * This is the implementation of event processor. + * All events are processed by this class. + * This processor uses processorJournal to persist and recover events. + * * Created by Serdar Hamzaogullari on 06.08.2017. */ -public class DomainEventProcessor implements EventProcessor { +public class DomainEventProcessor { - private ProcessorJournal precessorJournal; + private final JsonFileJournal processorJournal = new JsonFileJournal(); - @Override + /** + * Process. + * + * @param domainEvent the domain event + */ public void process(DomainEvent domainEvent) { domainEvent.process(); - precessorJournal.write(domainEvent); + processorJournal.write(domainEvent); } - @Override - public void setPrecessorJournal(ProcessorJournal precessorJournal) { - this.precessorJournal = precessorJournal; + /** + * Reset. + */ + public void reset() { + processorJournal.reset(); } - @Override + /** + * Recover. + */ public void recover() { DomainEvent domainEvent; while (true) { - domainEvent = precessorJournal.readNext(); + domainEvent = processorJournal.readNext(); if (domainEvent == null) { break; } else { diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/JsonFileJournal.java similarity index 84% rename from event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java rename to event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/JsonFileJournal.java index 9379e7b5c..870d8d00f 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/journal/JsonFileJournal.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/processor/JsonFileJournal.java @@ -20,17 +20,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.event.sourcing.journal; +package com.iluwatar.event.sourcing.processor; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonParser; -import com.iluwatar.event.sourcing.api.DomainEvent; -import com.iluwatar.event.sourcing.api.ProcessorJournal; import com.iluwatar.event.sourcing.event.AccountCreateEvent; +import com.iluwatar.event.sourcing.event.DomainEvent; import com.iluwatar.event.sourcing.event.MoneyDepositEvent; import com.iluwatar.event.sourcing.event.MoneyTransferEvent; -import com.iluwatar.event.sourcing.event.MoneyWithdrawalEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -44,12 +42,16 @@ import java.util.ArrayList; import java.util.List; /** + * This is the implementation of event journal. + * This implementation serialize/deserialize the events with JSON + * and writes/reads them on a Journal.json file at the working directory. + * * Created by Serdar Hamzaogullari on 06.08.2017. */ -public class JsonFileJournal implements ProcessorJournal { +public class JsonFileJournal { - private File aFile; - private List events = new ArrayList<>(); + private final File aFile; + private final List events = new ArrayList<>(); private int index = 0; /** @@ -72,7 +74,12 @@ public class JsonFileJournal implements ProcessorJournal { } } - @Override + + /** + * Write. + * + * @param domainEvent the domain event + */ public void write(DomainEvent domainEvent) { Gson gson = new Gson(); JsonElement jsonElement; @@ -80,9 +87,7 @@ public class JsonFileJournal implements ProcessorJournal { jsonElement = gson.toJsonTree(domainEvent, AccountCreateEvent.class); } else if (domainEvent instanceof MoneyDepositEvent) { jsonElement = gson.toJsonTree(domainEvent, MoneyDepositEvent.class); - } else if (domainEvent instanceof MoneyWithdrawalEvent) { - jsonElement = gson.toJsonTree(domainEvent, MoneyWithdrawalEvent.class); - } else if (domainEvent instanceof MoneyTransferEvent) { + } else if (domainEvent instanceof MoneyTransferEvent) { jsonElement = gson.toJsonTree(domainEvent, MoneyTransferEvent.class); } else { throw new RuntimeException("Journal Event not recegnized"); @@ -97,13 +102,20 @@ public class JsonFileJournal implements ProcessorJournal { } } - @Override + + /** + * Reset. + */ public void reset() { aFile.delete(); } - @Override + /** + * Read next domain event. + * + * @return the domain event + */ public DomainEvent readNext() { if (index >= events.size()) { return null; @@ -122,9 +134,7 @@ public class JsonFileJournal implements ProcessorJournal { domainEvent = gson.fromJson(jsonElement, MoneyDepositEvent.class); } else if (eventClassName.equals("MoneyTransferEvent")) { domainEvent = gson.fromJson(jsonElement, MoneyTransferEvent.class); - } else if (eventClassName.equals("MoneyWithdrawalEvent")) { - domainEvent = gson.fromJson(jsonElement, MoneyWithdrawalEvent.class); - } else { + } else { throw new RuntimeException("Journal Event not recegnized"); } diff --git a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java index cfe0cfbb3..2d957268e 100644 --- a/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java +++ b/event-sourcing/src/main/java/com/iluwatar/event/sourcing/state/AccountAggregate.java @@ -27,12 +27,18 @@ import java.util.HashMap; import java.util.Map; /** + * This is the static accounts map holder class. + * This class holds the state of the accounts. + * * Created by Serdar Hamzaogullari on 06.08.2017. */ public class AccountAggregate { private static Map accounts = new HashMap<>(); + private AccountAggregate() { + } + /** * Put account. * @@ -46,7 +52,7 @@ public class AccountAggregate { * Gets account. * * @param accountNo the account no - * @return the account + * @return the copy of the account or null if not found */ public static Account getAccount(int accountNo) { Account account = accounts.get(accountNo); diff --git a/event-sourcing/src/main/test/java/com/iluwatar/event/sourcing/IntegrationTest.java b/event-sourcing/src/test/java/IntegrationTest.java similarity index 59% rename from event-sourcing/src/main/test/java/com/iluwatar/event/sourcing/IntegrationTest.java rename to event-sourcing/src/test/java/IntegrationTest.java index 8fbed333d..5a3f5718a 100644 --- a/event-sourcing/src/main/test/java/com/iluwatar/event/sourcing/IntegrationTest.java +++ b/event-sourcing/src/test/java/IntegrationTest.java @@ -20,16 +20,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar.event.sourcing; import static com.iluwatar.event.sourcing.app.App.ACCOUNT_OF_DAENERYS; import static com.iluwatar.event.sourcing.app.App.ACCOUNT_OF_JON; import com.iluwatar.event.sourcing.domain.Account; -import com.iluwatar.event.sourcing.journal.JsonFileJournal; +import com.iluwatar.event.sourcing.event.AccountCreateEvent; +import com.iluwatar.event.sourcing.event.MoneyDepositEvent; +import com.iluwatar.event.sourcing.event.MoneyTransferEvent; import com.iluwatar.event.sourcing.processor.DomainEventProcessor; import com.iluwatar.event.sourcing.state.AccountAggregate; import java.math.BigDecimal; +import java.util.Date; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -44,31 +46,14 @@ public class IntegrationTest { /** * The Domain event processor. */ - DomainEventProcessor domainEventProcessor; - /** - * The Json file journal. - */ - JsonFileJournal jsonFileJournal; - /** - * The Account service. - */ - AccountService accountService; - /** - * The Money transaction service. - */ - MoneyTransactionService moneyTransactionService; + private DomainEventProcessor eventProcessor; /** * Initialize. */ @Before public void initialize() { - domainEventProcessor = new DomainEventProcessor(); - jsonFileJournal = new JsonFileJournal(); - domainEventProcessor.setPrecessorJournal(jsonFileJournal); - accountService = new AccountService(domainEventProcessor); - moneyTransactionService = new MoneyTransactionService( - domainEventProcessor); + eventProcessor = new DomainEventProcessor(); } /** @@ -76,27 +61,31 @@ public class IntegrationTest { */ @Test public void testStateRecovery() { - jsonFileJournal.reset(); + eventProcessor.reset(); - accountService.createAccount(ACCOUNT_OF_DAENERYS, "Daenerys Targaryen"); - accountService.createAccount(ACCOUNT_OF_JON, "Jon Snow"); + eventProcessor.process(new AccountCreateEvent( + 0, new Date().getTime(), ACCOUNT_OF_DAENERYS, "Daenerys Targaryen")); - moneyTransactionService.depositMoney(ACCOUNT_OF_DAENERYS, new BigDecimal("100000")); - moneyTransactionService.depositMoney(ACCOUNT_OF_JON, new BigDecimal("100")); + eventProcessor.process(new AccountCreateEvent( + 1, new Date().getTime(), ACCOUNT_OF_JON, "Jon Snow")); - moneyTransactionService - .transferMoney(ACCOUNT_OF_DAENERYS, ACCOUNT_OF_JON, new BigDecimal("10000")); - moneyTransactionService.withdrawalMoney(ACCOUNT_OF_JON, new BigDecimal("1000")); + eventProcessor.process(new MoneyDepositEvent( + 2, new Date().getTime(), ACCOUNT_OF_DAENERYS, new BigDecimal("100000"))); + + eventProcessor.process(new MoneyDepositEvent( + 3, new Date().getTime(), ACCOUNT_OF_JON, new BigDecimal("100"))); + + eventProcessor.process(new MoneyTransferEvent( + 4, new Date().getTime(), new BigDecimal("10000"), ACCOUNT_OF_DAENERYS, + ACCOUNT_OF_JON)); Account accountOfDaenerysBeforeShotDown = AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS); Account accountOfJonBeforeShotDown = AccountAggregate.getAccount(ACCOUNT_OF_JON); AccountAggregate.resetState(); - domainEventProcessor = new DomainEventProcessor(); - jsonFileJournal = new JsonFileJournal(); - domainEventProcessor.setPrecessorJournal(jsonFileJournal); - domainEventProcessor.recover(); + eventProcessor = new DomainEventProcessor(); + eventProcessor.recover(); Account accountOfDaenerysAfterShotDown = AccountAggregate.getAccount(ACCOUNT_OF_DAENERYS); Account accountOfJonAfterShotDown = AccountAggregate.getAccount(ACCOUNT_OF_JON); @@ -105,11 +94,6 @@ public class IntegrationTest { accountOfDaenerysAfterShotDown.getMoney()); Assert .assertEquals(accountOfJonBeforeShotDown.getMoney(), accountOfJonAfterShotDown.getMoney()); - Assert.assertEquals(accountOfDaenerysBeforeShotDown.getTransactions().size(), - accountOfDaenerysAfterShotDown.getTransactions().size()); - Assert.assertEquals(accountOfJonBeforeShotDown.getTransactions().size(), - accountOfJonAfterShotDown.getTransactions().size()); - } } \ No newline at end of file From 9d2f0c6c71c2105d8468f4d3fe4526fc611ca361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 2 Sep 2017 23:10:39 +0300 Subject: [PATCH 353/492] #590 Add explanation to Decorator pattern --- decorator/README.md | 91 +++++++++++++++++- decorator/etc/decorator.png | Bin 21795 -> 0 bytes decorator/etc/decorator.ucls | 76 --------------- decorator/etc/decorator.urm.puml | 38 -------- .../com/iluwatar/decorator/ClubbedTroll.java | 15 ++- .../iluwatar/decorator/TrollDecorator.java | 53 ---------- .../iluwatar/decorator/ClubbedTrollTest.java | 2 +- pom.xml | 1 + 8 files changed, 103 insertions(+), 173 deletions(-) delete mode 100644 decorator/etc/decorator.png delete mode 100644 decorator/etc/decorator.ucls delete mode 100644 decorator/etc/decorator.urm.puml delete mode 100644 decorator/src/main/java/com/iluwatar/decorator/TrollDecorator.java diff --git a/decorator/README.md b/decorator/README.md index d2ba55afa..5f86166fe 100644 --- a/decorator/README.md +++ b/decorator/README.md @@ -19,7 +19,96 @@ Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. -![alt text](./etc/decorator.png "Decorator") +## Explanation + +Real world example + +> There is an angry troll living in the nearby hills. Usually it goes bare handed but sometimes it has a weapon. To arm the troll it's not necessary to create a new troll but to decorate it dynamically with a suitable weapon. + +In plain words + +> Decorator pattern lets you dynamically change the behavior of an object at run time by wrapping them in an object of a decorator class. + +Wikipedia says + +> In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern. + +**Programmatic Example** + +Lets take the troll example. First of all we have a simple troll implementing the troll interface + +``` +public interface Troll { + void attack(); + int getAttackPower(); + void fleeBattle(); +} + +public class SimpleTroll implements Troll { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleTroll.class); + + @Override + public void attack() { + LOGGER.info("The troll tries to grab you!"); + } + + @Override + public int getAttackPower() { + return 10; + } + + @Override + public void fleeBattle() { + LOGGER.info("The troll shrieks in horror and runs away!"); + } +} +``` + +Next we want to add club for the troll. We can do it dynamically by using a decorator + +``` +public class ClubbedTroll implements Troll { + + private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class); + + private Troll decorated; + + public ClubbedTroll(Troll decorated) { + this.decorated = decorated; + } + + @Override + public void attack() { + decorated.attack(); + LOGGER.info("The troll swings at you with a club!"); + } + + @Override + public int getAttackPower() { + return decorated.getAttackPower() + 10; + } + + @Override + public void fleeBattle() { + decorated.fleeBattle(); + } +} +``` + +Here's the troll in action + +``` +// simple troll +Troll troll = new SimpleTroll(); +troll.attack(); // The troll tries to grab you! +troll.fleeBattle(); // The troll shrieks in horror and runs away! + +// change the behavior of the simple troll by adding a decorator +Troll clubbed = new ClubbedTroll(troll); +clubbed.attack(); // The troll tries to grab you! The troll swings at you with a club! +clubbed.fleeBattle(); // The troll shrieks in horror and runs away! +``` ## Applicability Use Decorator diff --git a/decorator/etc/decorator.png b/decorator/etc/decorator.png deleted file mode 100644 index 35a7ef35db7e7aac6621d6d33116ad2d692a76cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21795 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 KIaN6BNcsz+?~j@Q diff --git a/decorator/etc/decorator.ucls b/decorator/etc/decorator.ucls deleted file mode 100644 index 88bea6987..000000000 --- a/decorator/etc/decorator.ucls +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/decorator/etc/decorator.urm.puml b/decorator/etc/decorator.urm.puml deleted file mode 100644 index be878bd91..000000000 --- a/decorator/etc/decorator.urm.puml +++ /dev/null @@ -1,38 +0,0 @@ -@startuml -package com.iluwatar.decorator { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - class ClubbedTroll { - - LOGGER : Logger {static} - + ClubbedTroll(decorated : Troll) - + attack() - + getAttackPower() : int - } - class SimpleTroll { - - LOGGER : Logger {static} - + SimpleTroll() - + attack() - + fleeBattle() - + getAttackPower() : int - } - interface Troll { - + attack() {abstract} - + fleeBattle() {abstract} - + getAttackPower() : int {abstract} - } - class TrollDecorator { - - decorated : Troll - + TrollDecorator(decorated : Troll) - + attack() - + fleeBattle() - + getAttackPower() : int - } -} -TrollDecorator --> "-decorated" Troll -ClubbedTroll --|> TrollDecorator -SimpleTroll ..|> Troll -TrollDecorator ..|> Troll -@enduml \ No newline at end of file diff --git a/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java index e309f17cd..edaa334a5 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java +++ b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java @@ -28,22 +28,29 @@ import org.slf4j.LoggerFactory; /** * Decorator that adds a club for the troll */ -public class ClubbedTroll extends TrollDecorator { +public class ClubbedTroll implements Troll { private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class); + private Troll decorated; + public ClubbedTroll(Troll decorated) { - super(decorated); + this.decorated = decorated; } @Override public void attack() { - super.attack(); + decorated.attack(); LOGGER.info("The troll swings at you with a club!"); } @Override public int getAttackPower() { - return super.getAttackPower() + 10; + return decorated.getAttackPower() + 10; + } + + @Override + public void fleeBattle() { + decorated.fleeBattle(); } } diff --git a/decorator/src/main/java/com/iluwatar/decorator/TrollDecorator.java b/decorator/src/main/java/com/iluwatar/decorator/TrollDecorator.java deleted file mode 100644 index d84c3a2b3..000000000 --- a/decorator/src/main/java/com/iluwatar/decorator/TrollDecorator.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2014-2016 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.decorator; - -/** - * TrollDecorator is a decorator for {@link Troll} objects. The calls to the {@link Troll} interface - * are intercepted and decorated. Finally the calls are delegated to the decorated {@link Troll} - * object. - * - */ -public class TrollDecorator implements Troll { - - private Troll decorated; - - public TrollDecorator(Troll decorated) { - this.decorated = decorated; - } - - @Override - public void attack() { - decorated.attack(); - } - - @Override - public int getAttackPower() { - return decorated.getAttackPower(); - } - - @Override - public void fleeBattle() { - decorated.fleeBattle(); - } -} diff --git a/decorator/src/test/java/com/iluwatar/decorator/ClubbedTrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/ClubbedTrollTest.java index a097752cd..fb86615c6 100644 --- a/decorator/src/test/java/com/iluwatar/decorator/ClubbedTrollTest.java +++ b/decorator/src/test/java/com/iluwatar/decorator/ClubbedTrollTest.java @@ -34,7 +34,7 @@ import static org.mockito.internal.verification.VerificationModeFactory.times; public class ClubbedTrollTest { @Test - public void testSmartHostile() throws Exception { + public void testClubbedTroll() throws Exception { // Create a normal troll first, but make sure we can spy on it later on. final Troll simpleTroll = spy(new SimpleTroll()); diff --git a/pom.xml b/pom.xml index 6212ddc05..5e3995976 100644 --- a/pom.xml +++ b/pom.xml @@ -469,6 +469,7 @@ adapter bridge composite + decorator From a745c5d8cea8f7371ec3abb1f7b3a09124ede100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 3 Sep 2017 12:06:50 +0300 Subject: [PATCH 354/492] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 64f833e2d..fd0bb7810 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ datanucleus.log /bin/ *.log data-mapper/src/main/resources/log4j.xml +event-sourcing/Journal.json From bd4247e864937824dfd510fb26ddf1e63f9e7bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 5 Sep 2017 23:28:44 +0300 Subject: [PATCH 355/492] #590 Add explanation for Facade pattern --- facade/README.md | 183 ++++++++++++++++++++++++++++++++++++- facade/etc/facade.png | Bin 33815 -> 0 bytes facade/etc/facade.ucls | 88 ------------------ facade/etc/facade.urm.puml | 60 ------------ facade/etc/facade_1.png | Bin 44417 -> 0 bytes pom.xml | 1 + 6 files changed, 183 insertions(+), 149 deletions(-) delete mode 100644 facade/etc/facade.png delete mode 100644 facade/etc/facade.ucls delete mode 100644 facade/etc/facade.urm.puml delete mode 100644 facade/etc/facade_1.png diff --git a/facade/README.md b/facade/README.md index 22ccd6911..66ca84256 100644 --- a/facade/README.md +++ b/facade/README.md @@ -15,7 +15,188 @@ tags: Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. -![alt text](./etc/facade_1.png "Facade") +## Explanation + +Real world example + +> How does a goldmine work? "Well, the miners go down there and dig gold!" you say. That is what you believe because you are using a simple interface that goldmine provides on the outside, internally it has to do a lot of stuff to make it happen. This simple interface to the complex subsystem is a facade. + +In plain words + +> Facade pattern provides a simplified interface to a complex subsystem. + +Wikipedia says + +> A facade is an object that provides a simplified interface to a larger body of code, such as a class library. + +**Programmatic Example** + +Taking our goldmine example from above. Here we have the dwarven mine worker hierarchy + +``` +public abstract class DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenMineWorker.class); + + public void goToSleep() { + LOGGER.info("{} goes to sleep.", name()); + } + + public void wakeUp() { + LOGGER.info("{} wakes up.", name()); + } + + public void goHome() { + LOGGER.info("{} goes home.", name()); + } + + public void goToMine() { + LOGGER.info("{} goes to the mine.", name()); + } + + private void action(Action action) { + switch (action) { + case GO_TO_SLEEP: + goToSleep(); + break; + case WAKE_UP: + wakeUp(); + break; + case GO_HOME: + goHome(); + break; + case GO_TO_MINE: + goToMine(); + break; + case WORK: + work(); + break; + default: + LOGGER.info("Undefined action"); + break; + } + } + + public void action(Action... actions) { + for (Action action : actions) { + action(action); + } + } + + public abstract void work(); + + public abstract String name(); + + static enum Action { + GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK + } +} + +public class DwarvenTunnelDigger extends DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenTunnelDigger.class); + + @Override + public void work() { + LOGGER.info("{} creates another promising tunnel.", name()); + } + + @Override + public String name() { + return "Dwarven tunnel digger"; + } +} + +public class DwarvenGoldDigger extends DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenGoldDigger.class); + + @Override + public void work() { + LOGGER.info("{} digs for gold.", name()); + } + + @Override + public String name() { + return "Dwarf gold digger"; + } +} + +public class DwarvenCartOperator extends DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenCartOperator.class); + + @Override + public void work() { + LOGGER.info("{} moves gold chunks out of the mine.", name()); + } + + @Override + public String name() { + return "Dwarf cart operator"; + } +} + +``` + +To operate all these goldmine workers we have the facade + +``` +public class DwarvenGoldmineFacade { + + private final List workers; + + public DwarvenGoldmineFacade() { + workers = new ArrayList<>(); + workers.add(new DwarvenGoldDigger()); + workers.add(new DwarvenCartOperator()); + workers.add(new DwarvenTunnelDigger()); + } + + public void startNewDay() { + makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE); + } + + public void digOutGold() { + makeActions(workers, DwarvenMineWorker.Action.WORK); + } + + public void endDay() { + makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP); + } + + private static void makeActions(Collection workers, + DwarvenMineWorker.Action... actions) { + for (DwarvenMineWorker worker : workers) { + worker.action(actions); + } + } +} +``` + +Now to use the facade + +``` +DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade(); +facade.startNewDay(); +// Dwarf gold digger wakes up. +// Dwarf gold digger goes to the mine. +// Dwarf cart operator wakes up. +// Dwarf cart operator goes to the mine. +// Dwarven tunnel digger wakes up. +// Dwarven tunnel digger goes to the mine. +facade.digOutGold(); +// Dwarf gold digger digs for gold. +// Dwarf cart operator moves gold chunks out of the mine. +// Dwarven tunnel digger creates another promising tunnel. +facade.endDay(); +// Dwarf gold digger goes home. +// Dwarf gold digger goes to sleep. +// Dwarf cart operator goes home. +// Dwarf cart operator goes to sleep. +// Dwarven tunnel digger goes home. +// Dwarven tunnel digger goes to sleep. +``` ## Applicability Use the Facade pattern when diff --git a/facade/etc/facade.png b/facade/etc/facade.png deleted file mode 100644 index 5cc6271da191800a89fd596dfa1202499f210274..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33815 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

        7dHXc%oilFv{QwfjJLqXoK*+}VDf{o4K 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/facade/etc/facade.urm.puml b/facade/etc/facade.urm.puml deleted file mode 100644 index 477f9eee7..000000000 --- a/facade/etc/facade.urm.puml +++ /dev/null @@ -1,60 +0,0 @@ -@startuml -package com.iluwatar.facade { - class App { - + App() - + main(args : String[]) {static} - } - class DwarvenCartOperator { - - LOGGER : Logger {static} - + DwarvenCartOperator() - + name() : String - + work() - } - class DwarvenGoldDigger { - - LOGGER : Logger {static} - + DwarvenGoldDigger() - + name() : String - + work() - } - class DwarvenGoldmineFacade { - - workers : List - + DwarvenGoldmineFacade() - + digOutGold() - + endDay() - - makeActions(workers : Collection, actions : Action[]) {static} - + startNewDay() - } - abstract class DwarvenMineWorker { - - LOGGER : Logger {static} - + DwarvenMineWorker() - - action(action : Action) - + action(actions : Action[]) - + goHome() - + goToMine() - + goToSleep() - + name() : String {abstract} - + wakeUp() - + work() {abstract} - } - ~enum Action { - + GO_HOME {static} - + GO_TO_MINE {static} - + GO_TO_SLEEP {static} - + WAKE_UP {static} - + WORK {static} - + valueOf(name : String) : Action {static} - + values() : Action[] {static} - } - class DwarvenTunnelDigger { - - LOGGER : Logger {static} - + DwarvenTunnelDigger() - + name() : String - + work() - } -} -DwarvenGoldmineFacade --> "-workers" DwarvenMineWorker -Action ..+ DwarvenMineWorker -DwarvenCartOperator --|> DwarvenMineWorker -DwarvenGoldDigger --|> DwarvenMineWorker -DwarvenTunnelDigger --|> DwarvenMineWorker -@enduml \ No newline at end of file diff --git a/facade/etc/facade_1.png b/facade/etc/facade_1.png deleted file mode 100644 index 6ed0573fc56cd216e926b7c538b516f7e921e8b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44417 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 J6`ivR`Y#8bhkpP7 diff --git a/pom.xml b/pom.xml index 44461b091..cf1bf9831 100644 --- a/pom.xml +++ b/pom.xml @@ -470,6 +470,7 @@ bridge composite decorator + facade From c13661810efd3f41e96aec3d94a6d91b0eb6948e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 6 Sep 2017 22:31:21 +0300 Subject: [PATCH 356/492] #590 Add explanation for Flyweight --- flyweight/README.md | 95 +++++++++++++++++++++- flyweight/etc/flyweight.png | Bin 31900 -> 0 bytes flyweight/etc/flyweight.ucls | 135 ------------------------------- flyweight/etc/flyweight.urm.puml | 66 --------------- flyweight/etc/flyweight_1.png | Bin 63947 -> 0 bytes pom.xml | 1 + 6 files changed, 95 insertions(+), 202 deletions(-) delete mode 100644 flyweight/etc/flyweight.png delete mode 100644 flyweight/etc/flyweight.ucls delete mode 100644 flyweight/etc/flyweight.urm.puml delete mode 100644 flyweight/etc/flyweight_1.png diff --git a/flyweight/README.md b/flyweight/README.md index 469bb8626..9a0e13e19 100644 --- a/flyweight/README.md +++ b/flyweight/README.md @@ -16,7 +16,100 @@ tags: Use sharing to support large numbers of fine-grained objects efficiently. -![alt text](./etc/flyweight_1.png "Flyweight") +## Explanation +Real world example + +> Alchemist's shop has shelves full of magic potions. Many of the potions are the same so there is no need to create new object for each of them. Instead one object instance can represent multiple shelf items so memory footprint remains small. + +In plain words + +> It is used to minimize memory usage or computational expenses by sharing as much as possible with similar objects. + +Wikipedia says + +> In computer programming, flyweight is a software design pattern. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory. + +**Programmatic example** + +Translating our alchemist shop example from above. First of all we have different potion types + +``` +public interface Potion { + void drink(); +} + +public class HealingPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(HealingPotion.class); + @Override + public void drink() { + LOGGER.info("You feel healed. (Potion={})", System.identityHashCode(this)); + } +} + +public class HolyWaterPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(HolyWaterPotion.class); + @Override + public void drink() { + LOGGER.info("You feel blessed. (Potion={})", System.identityHashCode(this)); + } +} + +public class InvisibilityPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(InvisibilityPotion.class); + @Override + public void drink() { + LOGGER.info("You become invisible. (Potion={})", System.identityHashCode(this)); + } +} +``` + +Then the actual Flyweight object which is the factory for creating potions + +``` +public class PotionFactory { + + private final Map potions; + + public PotionFactory() { + potions = new EnumMap<>(PotionType.class); + } + + Potion createPotion(PotionType type) { + Potion potion = potions.get(type); + if (potion == null) { + switch (type) { + case HEALING: + potion = new HealingPotion(); + potions.put(type, potion); + break; + case HOLY_WATER: + potion = new HolyWaterPotion(); + potions.put(type, potion); + break; + case INVISIBILITY: + potion = new InvisibilityPotion(); + potions.put(type, potion); + break; + default: + break; + } + } + return potion; + } +} +``` + +And it can be used as below + +``` +PotionFactory factory = new PotionFactory(); +factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818) +factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364) +factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818) +factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489) +factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489) +factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364) +``` ## Applicability The Flyweight pattern's effectiveness depends heavily on how diff --git a/flyweight/etc/flyweight.png b/flyweight/etc/flyweight.png deleted file mode 100644 index 265d039247511ce2668cf1f620612dd4200bc3b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31900 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 diff --git a/flyweight/etc/flyweight.ucls b/flyweight/etc/flyweight.ucls deleted file mode 100644 index 633e385b8..000000000 --- a/flyweight/etc/flyweight.ucls +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/flyweight/etc/flyweight.urm.puml b/flyweight/etc/flyweight.urm.puml deleted file mode 100644 index 648c223af..000000000 --- a/flyweight/etc/flyweight.urm.puml +++ /dev/null @@ -1,66 +0,0 @@ -@startuml -package com.iluwatar.flyweight { - class AlchemistShop { - - LOGGER : Logger {static} - - bottomShelf : List - - topShelf : List - + AlchemistShop() - + enumerate() - - fillShelves() - + getBottomShelf() : List - + getTopShelf() : List - } - class App { - + App() - + main(args : String[]) {static} - } - class HealingPotion { - - LOGGER : Logger {static} - + HealingPotion() - + drink() - } - class HolyWaterPotion { - - LOGGER : Logger {static} - + HolyWaterPotion() - + drink() - } - class InvisibilityPotion { - - LOGGER : Logger {static} - + InvisibilityPotion() - + drink() - } - class PoisonPotion { - - LOGGER : Logger {static} - + PoisonPotion() - + drink() - } - interface Potion { - + drink() {abstract} - } - class PotionFactory { - - potions : Map - + PotionFactory() - ~ createPotion(type : PotionType) : Potion - } - enum PotionType { - + HEALING {static} - + HOLY_WATER {static} - + INVISIBILITY {static} - + POISON {static} - + STRENGTH {static} - + valueOf(name : String) : PotionType {static} - + values() : PotionType[] {static} - } - class StrengthPotion { - - LOGGER : Logger {static} - + StrengthPotion() - + drink() - } -} -AlchemistShop --> "-topShelf" Potion -HealingPotion ..|> Potion -HolyWaterPotion ..|> Potion -InvisibilityPotion ..|> Potion -PoisonPotion ..|> Potion -StrengthPotion ..|> Potion -@enduml \ No newline at end of file diff --git a/flyweight/etc/flyweight_1.png b/flyweight/etc/flyweight_1.png deleted file mode 100644 index f30225aa0413f756df9dde93f191b8b79f614938..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63947 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%0AN4z9t8| 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

    + * 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.dependency.injection; + +import com.iluwatar.dependency.injection.utils.InMemoryAppender; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Date: 28/04/17 - 7:40 AM + * + * @author Stanislav Kapinus + */ + +public class AdvancedSorceressTest { + + private InMemoryAppender appender; + + @Before + public void setUp() { + appender = new InMemoryAppender(Tobacco.class); + } + + @After + public void tearDown() { + appender.stop(); + } + + /** + * Test if the {@link AdvancedSorceress} smokes whatever instance of {@link Tobacco} is passed to her + * through the setter's parameter + */ + @Test + public void testSmokeEveryThing() throws Exception { + + final Tobacco[] tobaccos = { + new OldTobyTobacco(), new RivendellTobacco(), new SecondBreakfastTobacco() + }; + + for (final Tobacco tobacco : tobaccos) { + final AdvancedSorceress advancedSorceress = new AdvancedSorceress(); + advancedSorceress.setTobacco(tobacco); + advancedSorceress.smoke(); + // Verify if the sorceress is smoking the correct tobacco ... + assertEquals("AdvancedSorceress smoking " + tobacco.getClass().getSimpleName(), appender.getLastMessage()); + + } + + // ... and nothing else is happening. + assertEquals(tobaccos.length, appender.getLogSize()); + + } + +} From 2830a407ba70b5f47ce2462def0394d0ebde3c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Fri, 28 Apr 2017 12:19:57 +0200 Subject: [PATCH 239/492] some fixes for testing in event queue --- .../java/com/iluwatar/event/queue/Audio.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index 9175eeffa..b482acca1 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -52,7 +52,7 @@ public class Audio { /** * This method stops the Update Method's thread. */ - public static void stopService() { + public static synchronized void stopService() { if (updateThread != null) { updateThread.interrupt(); } @@ -62,11 +62,12 @@ public class Audio { * This method stops the Update Method's thread. * @return boolean */ - public static boolean isServiceRunning() { - if (updateThread != null) { - return updateThread.isAlive(); + public static synchronized boolean isServiceRunning() { + if (updateThread != null && updateThread.isAlive() ) { + return true; + } else { + return false; } - return false; } /** @@ -83,6 +84,13 @@ public class Audio { } }); } + startThread(); + } + + /** + * This is a synchronized thread starter + */ + public static synchronized void startThread() { if (!updateThread.isAlive()) { updateThread.start(); headIndex = 0; From ee3744cb0a5ecd3ca6006b1222924aa08264c56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Kuprivecz?= Date: Fri, 28 Apr 2017 13:47:56 +0200 Subject: [PATCH 240/492] added travis supported sound files --- event-queue/etc/Bass-Drum-1.aif | Bin 0 -> 220938 bytes event-queue/etc/Closed-Hi-Hat-1.aif | Bin 0 -> 13042 bytes .../com/iluwatar/event/queue/AudioTest.java | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 event-queue/etc/Bass-Drum-1.aif create mode 100644 event-queue/etc/Closed-Hi-Hat-1.aif diff --git a/event-queue/etc/Bass-Drum-1.aif b/event-queue/etc/Bass-Drum-1.aif new file mode 100644 index 0000000000000000000000000000000000000000..f1eae69db029ffa97252279b94c94930d5f74ad9 GIT binary patch literal 220938 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 z z4Af|M&?ejl=fIQkMqCYlg%!?I^Bi|G$1rKCTf+?M zlWIn~DTIH>C&2BbxVvhJC#$FUv(8KA>V~w1&S<4nH>{tEKwK0rc$SnF-4Y#tXHdam5*{YzXLzQ_F{@?D9@9I9RA&1&}yqcTP4kI zs}O2yH9!}w_2{l8fqc^fdPcFRvi$@Vv>&6g_7>F3E{6_6u0qgij|*D=KtgABeBR2B zrInUM0F5;XaMknDTx1Z%dep8>tJ-tOS?EZ0adMJqr#2bk6abgNQ`*|D3)HzAbc8jA{IzD2 z>ed%L&mNDHIBC#rXCm6^Y(;yWE$F^84r8YgF5qN^EdmoK6N+)FqU_F0=#X78`J8Vi zvvbVMb4sFY_CoNXB|%%PH>eNz=F{7k%q6Fh8Q`ojDV^o|tkXuXaUA`~zGiyc7f~{Y zqIJ#?^w@ch*1KuId!NYEb*|~XPIukZmbx0S9$MS;^&ES)UTrVb8|>w<4bd@n4ZQ^V z2(7ILDrjv0qRuka+=_v}mc1&0wLyATCq=D`0r!0;Ev)Cl(Vm6o zQwxA9mJp_qH^~lpmDG}qBv&;_71f74QT6Czc@JEHRe^r-oL+?tjy$pe87E`#XZXuq zpeo@uaO8JX*YF0N8MM(I$VfeeY}2KIY_T5il3&mVSrYXCZ`5!Ri~d44bi8bd?@2!p zg{FWH_yu~Y-a?o6j1k~k{HSIa4inp)>R(h%{Y3TDZ&XFShwsnA&sUk-YP>nEhMH4q zlDVJ`n-icmIiYKs^FR`QsH>P4Drlam|IA_a#Z1s0%n<#;Of^N#36sw}(?4LfF#_(- zV$!Q`Fb{nTYrjXpo_}IWC}}=`_GOwrfPp=LD**>Ci(U-5A&<~Vl>xPo=TIm42(4D7 z&>b}y_)0_343!x4+cV4sS<&o})y!Qv5H#FNa5@=7u-rR5F_6lru>Id6LwWr^y64nY@>Efgn5D_&tiDe^mk$C67XPyq8HYi|L~>wcaj-4uTG0FlZOv z0?E>n34m)>+!T|Y^m?eQ(#vh?jobpO?De{kJP)5^5`9e#1D)mxVEFshO;D~6*40%f zJx>kSzhOSz1az7cRIHhzrkQ9JWqiQOJ1QIM5#q8gCEDqvqM%M9>Vp^TxPB0@-8nWB~(V4`C%0S z>XhALgv=tIh#@iq|0r8SlF~fhNnYXufuT1`uIC$MT0UG<<5@v%beX+nQ`iaCof+1W zk7k1eW{X5yc1dhvufz#}UtsX8Pu@NSh295RSw@`rNc)UaDv$6aC`PQ+?3Y}PvsrMuX$mwC_C*nXPvy_ ztWx+Pn-}iEeur!Fy5TOoOLz@$8D7bgh3m5up$n{62*Lcl6mtVxJQbMCoWMoMz>D(E z2OoM(LY2b7(4_D)&@ZJ3jqpZ=%6RvKUs<}~6jn6&4=Wb<&Qb?Xff9Q>%<+q|2L2mt zfWIRf9QTD)i;MMi+oC(j)1HFiGk1lO|abvT=K^ScKE*p_W92TZu+MO zKKh3R&iK~^hWmM-c%We*VW5A21X>1AAdCN}U-~bAUtk7MwAuus{EY%F{QUxb{W}7i z{BHx#{5+V<|2CM}zay9g{1I>bZ39RAlLL$4RTc+I1hxg1fsX!0;91~6zy#U_a|cp@ zOFj_HA4m{*8z>W)5EvK87})9m5xD686SyA85C{g^2eSm`1giyh2Rj9h1{VeH18K|- zehC%}eh8Ki9tuVV`vr~%iwA}T^9H&H2L#px-vko@lWcP6T<~v5h028Ughqwyg_efL zg%$!It5tYpD1A6@FdTXrRH0L$RH6H!{NbFy^V%31>J<#F@|K78{(quFAXJ?t4!&dM zg3DRQ;Al227|W)GlCnvmoosnHC-htbI2 zWf|lU?_Uw;tq=pf^CAb!B{H(L;1>3aojjTN&X`OJ=Y>>krOeI-$zrUdtiwjgcI>?D z0*>Kc{J2~sipo1;naUtes{GBSITNVL(_#3)@s9M)OHYvl)}+kG)Z z-2qqcFTMl%-0k&D$XwLCzM00`froC_2*S%Rm?mPIIVGMLE?XH--ZJOG zPc=%lHdVj}P(rOXWng++SzQE1^KKKVy6B+FZ;;AkvZ?;2gN`)QfYH3$Bm-K0YV$*X zLR3RJsdR8>;aa0J=_l*#ruKNxzp^$y-;l&0du$)&>0Qkt9U#<3KR2w zS`7NJlW{f+q3hNhw9-zFV(hW#qJ0v5g7xDEdkL^|+e5#j5vpwuL*N5N!<-!Giqi>r zS7Y%|XDXiWY`~L&bJWxEu$&I-FA4F^BIqE+5#)g#%mmk zuR8tkb2kV6=|00jaQ>$T#(Z60YckM>$$0lX=>pGh=Ke=|`m&I*zNKUZ)c&y%1IVL@ zSu{aJQ5x-ANDsTxO7HHoIs$8;zOSN{$#=&>5yh-55pAq45lO9m(2EGVAv-w`KvTOX zE#@m_-S&O7HUQJ0f5bOybi`e2aYO^_EIjTq?Bk(Z&-&q}u)=OyJDwYD#|NHGMt8kk z!QEqzarfKL-4jke_lVQLz2&5F-`QJS37Jne@W$eRycA>Ya1&V%oF*_w-fx|?TU#UT zp%&07pdZtWmUd!Dz}ZS8oIZ4blN;u~N$kv!nsv|FWh-!CYqnxAeCg+wr z$m!`ufV%@yCY*#;LHiulz`LkykFoCAjqUDsdi#U*-YH~lcj{R~VP0OverIK}XTdhu zs%Kxa&N`j#CJwW&yMvwd?kcB@8{<@P`#O2tTJS0rYytGsZ*B(rBKU{vuiq!?C#DsyN&bSF6(x%xO)~p;amTol=a*BZP#-K+dG{K_B#it z4Ng;gtuxH-?R>Vo0r@n>x65%N+BkzEmOC3G>N>}K&zx9aEoY@0a$31poc!)zC!H_a zY3e)Xyp3?(G+!>avv0LqCnArVE26*aMnt>NxPZ)o ztL{MG6QIOqaJ`5=?#GA~?!<__Zv2Q?XIsQ2r+>s7c;!#d;)t!zgNQ=I#LRYarsd`#rLndm!?w z+bUjbN5+eC4n;n87DZ-o=0=Qgmib;eGkueQv{ly0E;;6?czY#GUP0Zhz;G zTivB@dN-d-+|JH7cfRw~z3ja4B>={4ZMU+oqdV1C(>>|K?sRv*^W5zTX$_5R+pTK# zcC%TPotIX3@C)sBl37>m8`esDFZ|VP11I=gdI2bXSL{6WEu;ka!IAVCzCU1(0z%#- zn%C|?{B~OM9Ef-qtyQ2w>P6ODEy!4_DXD8UBZ;gM_=klcvE&3vO2?2^v>RDNr;&f* z`zw@@RZxd_fRqYF7ej}&9mcd0ng&S%1!+lCgth|T{sx=`*c?abXHo!W^VKNDLE_+6 zCo2z0yFqg+5nr~|X1S->_viO<0_ zK0eM>~x4gtOq)a6T=DPN4UY5OV}=fON*kI0^m-#{iL`3?4&ff}5)k`hxGGdFV6h zZ9KHx^u!dpJ+sV7>_Jb>L6h+=)ElP)wb4|Q8KuzuOju`wEV72EtbU35n6+pXDv!3q z9*)BKeh=ycbE+C>8uXb~qYCH&>WEW88e{>q5UvY7(Ik|}_{|!#(nOhYn!_yfDAc1v z%`KhJd<0ioVx0x{y9Nz2E#VotAlGIUd>a04wPNyzH zCR#I9R(_J}nqBxIE!xAneB!hw*^XXuu^ zq58wltNARxn&LH3$HRwoo^V;cDCFr-h?z3sqNY)JuqgsFxewtJdTMyT&L3W){)D@$ zE8)iKWVoT)6K<)xh3hDY!IQH?D`ewPIyoTtpZp%&sx}8V=>EZNCVlXNnHpqfTd1NL z6N)wI!rAoh@BvUQ#M3Rj?0SrsM6dS}=m}m{oyM!AmU#7m9-ds@32&0C0TDSqv_uXH z4V5cH59FutT-DYarY^GX>H#mSAaht=5{+eQF+`jf(c&s+G83O6r}BT~O`b$vu7qi>}DHlW&-RDN(rj8 zzapJkD*D5ebPjkCrox)4pV=lVAk06Y61)y-&W@pJtR4Ern&7!?8Og{P>A>5Nocsu$ z&p)9jK!>jaoSSd_vH8XCp_2S2I>mu?%s1dMd@vr)+u|tR5<9#%y1^%)t9&x(4|?I= zyfJ>khm#_pU1=yrg4#YWapf_5LcYU&AwMvmERB@7h6M0*5{a{*es2p|B~|cANLgMA z)RW|tustBN9acJz|N@4V~*-Xq_p9CYp+{YKrukWQxo0__jHu`|xW%B7( zW~9y!Gpa-;8jcL33+Pk287LGwX-{`DwRK}S+Dn^(IyrQbe(D|2MartqsjF(AI;;+A zq>jVUcv0U{J56HM-6U5D^;daa&yzQGdeG6IQ$N)bsg=~{dI0VNaxp(_o5T%TA-FFslMx!z!~_aTc}HL zWM0t^VKeHg$p>ARda8oy0I5WcKxfU!LZFt~iGPSp_y%8z_wgt^lPAT^cs869 zdP=EzU0jLh!VB3m{DTcA1z09h*87iS^S0w(-Uhr1G8{+1Ty!9-iZ?O~-|@QOZ{dmf zW@sOt1HGZ#!CUB2@Fm(CDvfT3F5q0j6Tau=#UU>XJ{*398-^#N=i$z1Zg>Hz z3cfYsO*0R?JqMw)`b?KHK7R9FnAKYW@o^2rcC+J5|ce#%cO^MQo!4$ zHvo$vF{`B7u*&irD<>PXqEG`CmSkZqynd=~y8 zj(W$$EATy)V87*1_CpS0%Vi?gTnuAP`7<_=_h9FFMfRGvU@!Pswg;y9BX~Vll6?cs zz(DVrCm@$_zt;m4Q!Ttl-Z)km6aQw|6l7)B70i&nkvI zwkI@|Ckkcc4TE>V$+4F&4_@UbLYO}fb>cTepZG!W3`_%^R(G#H_y!_)>u^UtAhexN z0_VrPP-{LibcR<9S7IjIlidlIWoJX1p~FMimEdglBshtE3Hmt=9pG8R(|Jv=DD?x6y@85+gy;fJyry0|{?eocv)Tt zR1lYVYL=S4@}{zb(B)d{4F~5M9pk7jz`l^zt+wz*4D2u8}Vu;EO)R3~gs%ppct3}Xhe8;)21t~^{#9!zW=P=#j z_}wl3GY`Zv6DI~4DTYFQKf(k>cgVI#i7b8q*l6WZarOa~WZO|Hw#X>9#Qb6BP!5hD zZKNa42zs>rq7EqnI>puEAJ97PAg_2Ha+N(N>)1!Q2IVI{P%j+h^Kn-`66fO;adw^$ z*W+dIYS5Vz=dTTt}O@SmXOoYO`OIP#WQ?J)+AIuAyuK*K0s|F4b>COmB5{JF?3Il zL+$i)RLGP?-~~n9%vErmIp`KDguXy#LOhfY=Q0M@H!txp^BFIJY3(vJ4ir~$xC&@d zliOYjRLbQY~gv(X^b6;$w3!Cf1|uR*&%4s`bcat|`VIHjQOzeY}y>0}-0 zPIi&uz#CXk-JrIZxcF zZb7Jxx;UfU-cDM#Ce%N`>UF+4j&sn-D> zNY}yFST`p<23)2~&I9jWqknk$S2YZNL=&nk)R&mMef_n$zAYu9Jg+g>A5n_u<2IHtt3j;7Cv+zoGx3ck~x7ZbjgQRx11sW}#uL5;P!-_^3ABD6&1+l+lsp5?6}%9Rnt_Poil_mmXe%%qF&q`OP*qTa3mj!`;DlxeWR@%k zm**n%9J+R4^8m+(XQV&{p>iw;N01MfgEW%1W=J96>J-Zwu3sUlzC|W zg{-JCD4Q7s8iaMAReS<;$w)K?obfvmMOWc{pN9MAfSxG|R-s8?{`eD!em1;v9`pYH z8B=3SZ?w~-M|UCp?lHJp_rYqXm)?)EYY9PWeNZy!F-Ds|XbI>Y&q2oL1(OyM^X{Mt z`U*JlzoD`~|0`~yfp6IY&OlwE(j5fa$tl1KoMi^WS7OHK2cVBgU?BSwSePD~fYPG# z5OZ|}>f2?e0X(xJ^ger-BW9b4HD}FJaOzYrl|V1?2;I-1)6U+(g%G27FVf9p%Rd>}y^+m<%gs{FVrtU$q_kHyZGZoqy&IZ_hTeZLsP}$g+6r zSWmAvGhQ#g)|)8e!EB(aw@K9SwutiHeo@PN2P*oEVhigaVqqOIovjyj*j7;#<_6_i zU(tkR5xu-a;C=53E1rs?xK~YNh1;pU86t(Z9rkyW`@LiQk$09~hTAv12QaDo%M~ln zB^%ElvJ-qa+rg)??tHKZH64%z7KCqtUw<#(5&prCc$N7vFNUx4{^M<7GME6Ip)b7v zyU!xH!{YOX-fte`t>ABgKM?e?z-zVU_u;;+Y(AgJ6Y#-2KOYFW-)-46o*mxr9`6`S z>80O4@@9kc7Z)W(rH$VKZcOd-3`|5RpJ;r0**j2Uwe)|}H zhAo9{ILuXx@(3U*MskhEs=`HsbcuU~cQty8$<4?S^-fi!Sx63=~P4*^w z!@UmP3a^{@95TR*FbBL0{o!5TW~F&5?*+JN$FhfBW!Bv*$I^MtJ?YJ1Nxj`Hv-cm% z?!_?zx#(ZnVDBZ{>-}K=u`KKjyyK7TJPY&0JPU8dJM)=*17FUc@;N+?j}Vc3tVqXq ziK5_FsK~#G8vLS&hWq>SJYow^3~ucLG6A0{lk=cpqJg*|CW?)smpCEH0Gl=>pYvO= z7Tlu~@}0Ui_-|W_6uPgNtye+M;dJa1MplM!?h2?2WTY*X!_k`mDbYYnF-diUWX)M#U@ZFx)V{jzop7nst&Lz-2T!NP49w-K!LOpQ>ln9jY&+#L( zlTB$d<0!0sSzU`adWa1|0es%BJzZ0 zq=@#X#b6r%4z3fxdP+>F)fe}*VsU(H2QpSiT#&}$sdOQ}O`G8Fv>E;dS#9C}S1fHH zbLe{Vn=YVL=}_212ilG{qe*E`vI%&c1?Wfo6_id7t+H5Hxk*m?hm-{8X-2w|V7dc8 zrRVW=aG34_-|AZW1#h7@aF8A*Gk_^om0qSF=})VI!Io*G&4$angKT%>2n zM>>HP0>4>X@`siuH;6~R1Nks3Ne-)pBXk5_40EMRG(V{T+1Xz}6+0O}qj$j1x(ENJ zB}r$v_Z#U=8<3vR3EoQU6GJ0uHFAJfCF5u|(u?>>YjU2{A=^k{@Ng9cw`eoCy@ebh zapWpI;vTI{ZqbI|o~;l2sSM=qlK34hjv=9gWCQQpRGI{Gj*pVpWF$F7dVr^EF}&(+ z5>4Zi>Y((hOLLP-@R)QI;a7y?tu!6p2oAVUv>)jU?=1_d1bib*{bxO!j>VwZFH=RN&(08;YB#}0^F4Nj} zCYs%jA|bmZtj`ick32yBv;2@8{8Tl9cDZ!v;1ZPEcoE}ngp40T` z4s7p%gPxiego$5v+=?)8U7WxP$ar*{)J5ANXYC-Y%WmO6=qWxAUcVWr6Rr=;;dtP+ zeFA#OlV$>VZReo<<_LHy;-D%i3NuUK38Tek1{!73L6+?^=xROC&vX#3;+b`8xJr-K zae9ZIs4s!f{R(JzV%2gz3%23vz8weJnY7hUK=&HK8rr?9$q8q7pI+e<$_5xd? znJT1`t42VF=nc1e!}Yqfnjyccm7unt4=$W(a4jAtMyv5+C#dvoHA;?DT|lv4MZN}_ z^f4JLCj&pFmDnSrL==#wBV`jH0z?6Iy0|C>By8wIiHp(|ancf>#8+`#yc1o;H+W10 zpDoMre6j=ccuCkK~Uiimim{BSDe0g1@lAD2ny+v%32jJ^%_}yReJ2J>8!p|G2D!jLv&$p`2;4`Ww z`s)?I!M+OI>ql}V_zHIDVe*^KrCLH2&eTx7PE`cJqpZE}E%olX-r=IWymdAf*na<+0`o-v{*XHD)}YVa7nl>L}jN^yIxv zZQdAMJ!QZ}Q9_4!CzF7$GIjV9Gn@Yg<lz>(wQ2ebg*qnp zD@%gPLM9O#Wn$1)^bl!4XH^&WdRUi*t6dk_Rkx8tbbDDvj}l=WE7s}jqNlzlTIyq< zmH>heeE-BCam$nti%edTRSUir9DiB#A@;x|V3*8s2JBhh1l{N7(PxndT@annYS9Y~ zh0c5%t|5i=n2~&&InK|*rvj`7f%G+gR~P0Z)NGz!)!?>T%4_Ku{uii1n{hA5a&0Gb zkWJzxX)TuHm7+V)f(9WhwgXY|mzga~niFy$q?5*=9H3}SCoh>Na-$h3hXJ#zfyn|t zt0rHXNos_7q7$HEK>iv7SJ@cQPOs7fK>OU;Fx>`Jm0fgLPteEoZa8!N23kg0)4@!G zDcD}K);usH5NIO6)l~!M05$a;a~!;5@xgmroEYSz$ZRCfOad|;SU;I{3%p+sz&&&< zu5RK%&DIKUHM58d*XcH(4nJV#lCS|khnYx+LbCco{hPvXL)U^zeYp~Jhb}@7=q>a- zD9vLa^ShOqK@-FCUYXhCky%8(nXQmZeuFjuPR2Zxg6=~lftOLkBB+X00A;X>njcmw zbD3T;S7}>FNM)!wIfx#S7+j6)!qedlJd|w3nLvxbfLL(0J#LP{b^yF?lC(tK$x(Cx zNZ5bK5@08!0=MxZQ~_w|31L16?*-Mzo1v1vg*)M6_zoTh428^4e?P@tz;pKj9YPDx zQ#277(5q)b-*G8$)Rn>DdO;7-AG8@=LF3Rin3tY_>Ek=_+?B*B@o2mduLUyuP|_AB zCGCJgnGu!1qfs*S5~h>?V<1Jrb4TKG=oM}ae!gxvF>V0d`P`sh`HnKe+%!LU2qr_l z`Wvd|&L}?K4|LREA+#Y_v;kYX3_A7yFyB+F}mzgK{w26k!K}O(rR>%Lx(pi98QFVQM@0q!@q)4|Y z-Q6MG($d`}-Q7y5beEC>0@B^x-Q8Vhc6~qJ=X-p{!##J-xhH03ul27LkCknYC=Eh3 zABF!eI`TuTdfVhnvD3>XcJUW>ljOOM<7%AuNp$lQh{k>*(cF(M>XFi!#n0^a`!!r) zvhVi!tL+s35}M}^E{?BVFaNpw$6x2x`b}L&|0|c&7xsu>&d%_!+9AP6+c7Gzt)mLs zmQg8e&)~FWQi(kuq;yIAw{9dU;x0%oMg~R2i=dTEAB>hMf=MXb2a3KyLybq- zB6rEJ<$hS|nIe@e>kfc;%n?^XOm6-Ec8zX-8Jt)rydvK-Qy>*y%OY+dsag%i8OL$x z;>aZSt_Z;-w%C4P6IoGU-*ehbauK{;zG)(onlYjz>gdikgP35ei$84^G0AKY9hf`g z>-lcIZsA7h=5Do~F4E|;VvT+&Gvarsjq^9FZo&-e3}P6(O(U45);d33z+iC>W>Dxy zGO>{|83^sy`lJYX{6pPIJkwo-)zeW|UzG`&Gy90YvlIt$6TMed!d2W{w-HO(=PCOn z*L(OI&p>(K$p-ok$+8DzO}$L!M4g>bujh5Vluck6SDSJ2x!Es2n?rJ)St$#fmf{4R z$YOn$jE}oAxrr{vn)320$z;jQ9xsbwLIM+YZ`yBUcbh<5u<=AHc&HIJhD&dS!%6C5 zvyvt;i`ib?OSbKpm)0rdaY}$ z_w%XWb;I;CS6)B1*Y!TzUr)28bqiZi|7d?ezuizTv!l#6cDEU2t=UK2unI+XU9SAM zT`E0#N+)@Uo|oGa+6(GWleu+7OCOr53?B?zO?aK^Rv;D z<_|a9()_z{c*>>;9~q;fnK!B!8NzK?>&KYOJZ6zG?Xp6x4Nu*s=IoudZw4FSNgK{w9z?C z3fldHY$EK0%S|L2sNX_LxpHVqE2TwW|&630|M zuZr!?HXR?_Dm-yp@J9T}{PN%BB|BDbvD4)5_J|ye24INGCReyDINW11Ipm4AnmHwp zT`BJa)2Hu<1l|Er+uI;odFw?JZijoj#S`z8oaEi}a+0qyjZUyPeQ$Jp?8E)6vY7uP z9oAHN7%ymxAfx|PP}!eJ&U4%#ZP3!c8%*}s2cvNV{p61gzV-+CAN;;SY_=BuZ^0=T zm6HBzlAPm3wF?qNCH0>NOZ^?}J1J=8cMCrFotcl`BYHA_V2reW#~8c(vN1OM@nd9X z0(eWBkZCY0$^7Bb;`mpib?_fXd+6_sUeW&{dPDDM^pv=fj^Ioh;f;&d$J-Qbw)ZUB zC+}1A+TMfc^St%Z*LZEBkN1*9uPF~ik0&QZdmy_-yDEoAyDis5yDKk6+beHI8z8qu zOD_9HZIU^oI?EucB9lBT$_i0qs+UDd>8#*d)334n^2n z(@&2#f9V=#t&U-SRwqpY^*dL{Ub?2Ls^ih`N>xz3RTb1L)l{8QJwe%ftAAA;wL_&; zTf;|S;JZ|#aEXc@t_}BvN5i?{`*5v_7amgy!!vN~e}+?GzW+WAwhXTsee)p%*bY~fFE^*JN&Bk#lJk@L!noWtYtSSOAck}i!>kq>Hd zuMqzvNJlLx~@~Hb?S?% zsP2Y$nDaGM?FuWXnPGV{7h0(%;ds>?%(rcLkW7Ys>YH#^xH{Y#mJGLmlON_iJs`0m zLD)f6440`s;UymVoKNxX|NfmdoX`GMLCfDoY-CI1QDjCKC-Pg^II;kp!lLk>$fWQO z(Cs$r=}ny@sVaO*EO;SOSlPao(=1Ad=yj-!)z!R3aNp-pH|_YWCt0NCF*cY z{Tgml3&TBXTzHNNXxCs;ZgXV42+xNPd8V5vGY+6=*%28Vo*>&IUSzQv#%F87)w+@T zR<}~kK$#jV@@m45;WJo<9pPmD{xt~y=Bf`z@=YC2r&pR!dNV72b5%tZ0y8faw&k;} zPUg=LxS<=MQdQL%HHCfFs)cHvnyv<@si-cdk##X&HQ_91MS^8ZbxW00%al}g!_%RK zCAt(I4=?by;;L$75YJRjz1A~W<1^|4=rB^5wajsu35M2Bb>*zQ6o5e_k$>9)Ay<2E>IT^c6rGWDxs=?jl6T;gCe9<>0LoJ z01e)?Rg#BuGgvU9-YlPoym3668+#-(N$F!XTytRO^qbk zyS6Z4L!5a%$e&s$)`sWAPL+WvYK_DT)mz+Gb;ZA6JdMMK?tSE_n;7}U6(*G;M&z;$ z!@wm7W4rQ^cW!Ltq1yo(awc-c9RXom8M*6bM&5!0#c&hC)aV*>y2D{M@S%k66u(;m z0yi|$#FdI9cd@>_vsX|&t^4w?UB>OgNOZd*(uM7%T@u!}tHMzrBOUGRFqRz^nQ8k+ z(xLFYZU=lh!bF?THff|Rs?=qsYUHi{Lgv$P>c6XDDib4&$t*k{R4_JvnH1*NumEUF zH8VdPVwQ&+&9?BNIYWJUA>3=Og~QChVI4D%eFlVhpFt7_gbmCf6s;|IOp&l5wdMq^ z!gD4enI;86kgBWPC}Pi;TwzUB)Z8)i10yXX2@j)XEJ^Zfe?ecznJNx0|HlHj_KNOfCJDX|3vl zf6X^Psrx3gPN8qcSRK>fsB?O*7N(HSZ8qp8CL}ZUJ?X;7bP}>w z;+h(o=hoGY)D!eOy+ePXa<$asarFg*4^cnYxAji_TK{gM>(N@1!*oX9(Ia@i%B&ba zFyU{!?W#Z6S*DZy6#B^o#V>FN2 zr6I-Tj_G38m<4DE_pu$~-yDbLwrhaidb4dL64@Q1vinAKbw4o;swd2T8`KKlxdS8z z3`5gh#cp@G>~mMhk@N^}zRV4G58MFQ{mSs`sYG6;kK~4#FKs`<@TU>oS>Y$(5*m(v zydkpzqcd}G9vK4#N!PzE2H0(2X}d{u@Wo~juM{9k{oNyZ%zXm+y5ePY+q`U4x4GOw z?^{rS>>{6+M|AM&f;f#Q(`mC?;hkZ+-!41bTWHI8<84lFiml^qw0QnqdOxq5?GF<% z{ga|o5J#*Gs*4Q)8BoC?Q7uY{^ihRH5hl2gjG83wN6nyC93m@6)s_XKzGY5pG;ur# z#a~ge#ImSw#kHuaGELNQ-0*9qiMs3!jCw~Mru_8LV)}Wa2|rmh;l1X*V^OcXol&>F z6H&XU_vZLHqQ?2v*_uVIhF7`e=ZqHJPZ=$VpEt@fmF}QFBWjX=kV)##qFVZqC?>n& zQBYBx{V=M25I3qo5GyKW;87?&5Ad7^%luWraDQCT#qSV|A-QF%Um>{f*NYNlBR=r= z1-r>goEj8j%1WkSpnp7=a|IuIUKl3m7*Zj-=1%HWu z+;8Y__v4Uhc$M7MWBze+7BxIhYCnFE*?U7RIpcq9+z7dfI&5pgk?XqMOG%DF%Al|pBk<%CzmL4= z9g^p9g}szVy+E$;e7Q+pAl+shiLLqM9n@mm#c9y4Q?jbKf*$1w%ChHRZRDtkXR?9x zWNVp%6s=+)afO&CnStZ%F^Js;v?!=tL~n5x2g5UQ031+?=fY#6n}L30tZN4TTf!A~Ke)uM3A&RuE++THca{0MARdQOE(!O=af_@&JMzRm zvX{BNp7{b zi*mb*&5RqOqpJl1lgVl)U0(a%)wdDeb2?YY6+;_d58uUq=u9$8)-;Zatt6~(wA9mf zEzh^ozC{!MoM+turZbK!3G*auL6Qja^G@6H7yjbe-?>Uofb5)cg>603*Y~-^CNFIG z4p&N#avgPFHwlJ(o!;)w>#NS`drXGAA`0mfA}`q1_h3=qnJglQ`BhXgkMMmY6rIgu zQ56MzB7NB1V&&egMvzgP*WFP0gs=LG6ezbd>53w|-XIE@I802cA$~S}#Gj_WxM;ee zvTg{wUR`W7c|}M4N+i=$+VS} zCEL@L7unq{rZweb-cw$bWv_8>E+iSQvWNwWcHh21uXNYVw#Vq0wz}W!7&o2oeTg}Q zhoHDStWS_3xQsb`7kEci#ZhxgoVU3_I%|l9wuG2weKFVUAk({xSZoTAQJ6x+G~c@E zrnW0d21SPd&x;sjzPR1ymWXb4iRxyPm~W1Wr{*!pX#$zurjr?LYMIE!m){vD%bWYM zKNDxim<_TOx(3f&7E?h^)7i1^GRN2|j*%s{8xs@)D+igGK?Agn@vO)C4=`$Pt zb`5LOEVz|nsJ*)2W~hKFEEPxAeiy~(l>ru}1!vYm`-z?}J-=x#a5v5TeR&Z@ebNvxFNK>%^ZQL_AhxFQ+tiXNbH?Ei@h+SARI?};MHMZ->*|P9_sSN3T-J9g=IvPW zdv3K{h@P=N2)*U?|LrPq4CIB=PbW4yDW2NXGO$yardmggv#CTXGue{we)!GW8H%S6q7Y!qw!j6^4b5Zr;Nrf3Q={BRj;Lvy1SET`+~M z(hr@d{|1R(Z|CTzwmQ{VMwsoqrXi?gQG3NmR~fW=8;+F3`YKrdZuo#cqM=S8im7#^ zptf}n*)FR;+ynJY#Mk*m3*7;iNf)sS*U4~Q04~#WH`Q6USFLkT)n6hfIdq-W5u7V$ zMH{tW6ep`LF}&*6s+dTxQi+Tzi%6nMi#V#gh*DF;cX&rCs{3#WF>#+KaxZimluM~y zCH)<($S80p7RG>b`xZYp~xIx0velg~=`A zn>-@1spLL_oF6l%armX;+i1mHfl0W0{&~(C8*I-Sd{UQ09(U87bYIY#{&#iF<%&=t zG!pGOL;AZ}oIMjoT&^RFNYN?6dV0&{W?gNJe|`i%&vFORomAlHT1qS|ORYbHPnJoAt~Sh6Wi$|#Z5;L~<=RpojI-_B zMw{DxB1b5z`3+q|OVQKR5#6|QRYzZz+#GYadCU&8+^s|FaNHDh?@55qVv>j^Ca3tr zG#Bg52v)wiVue|XMs2YeV`jo~%@K>tMzO(MWPJ$5L?+ENVUlqj^IX(5o5io@7qK1P z#S1f9gl3C~7%N`0I=@coHiDh(iT&6a2Wf`+kHZz}PZ~LQcXD7=VcCAco|K_}(A?De^sDpb56bxd79YI3b zOmWPv6Cb$3r?i`7F0l1NcAPA2o636jdvNu5a*d54kJt?Iv@It$a)loQ7vIEYm-)K+T@au34Vl8Ekw2N(DDto>XZ)7#~JvFNV4-U#h?4EwxHMRd1x$4ZTeIq*vQ~>&-GhdizZ! z@1;rLedNCPdWiQ-SM^@$#H8ZCVrtH5KL=Yb_1KT5V|a&kHgB4)=JnMLycxQ!cSiU0 zQ|du}MLpK9rhEI}=tkZKyoRNb+MZGu@Tr}Z&DCw$Qm2tqbQ^g=|Klas@4ZYWke^6m zTL?2*NTcY}!!XB-GMz+0Gnss- z<>IgZX%=UT$QE!}Wam)wd9Xr^n~zs=8f zG1uOs<~`?jM%cmc-4lA!mw15xyJB=Od+28mpb0u{NshBc%{{bOQ6$>ccRo(V_S6mw zshEDFYOQZi@Ei+VIy;%FbBLSIOcQ2sP!E-KyQq(clfaqN9-@*@ZnyEs6>c6C(mty4 zOLVl)-33_x%%Z5Mf?7O>IEap2xdF^_NQoUE{eeABZFh~XIF|6ZKICvMP?oi30!lTR zlKkP=bkEdoVl682<#fh7-7YxiyCfHe;(>cC?z=-wYg)wW*-v~zw|*MO=I^Xvtyyu) zkjhbtDyOc!g5KmJeDY;6*B+%B+bP!CWn#abjw*eGxMqh?sf`g=x$n3=MlbzF^kgDb zbh?chsNQpOMT+7I5s)pKhC2LPyv-KGVGrw3U-QbAw7FQ{2IJ`5Z@;q-`RSG|Yj@hZ zw!dv>3&N}V_%iA}D`TYVTrWQKmF*TQ7J*N*JkFJ?3oXcmxKyU;{K z?Vb)b{C8%MiDx?Mm!_89VZH-Z`K*uYQ?Q^1OnH6QOh7gFAJ_L7b}grk1SG0E2-6?xC$kCG z^|5-!^CW`_%w{u!{-p$Ue4|$Jm=WeIjOj~qxnio4_B&O=CV^4Cu8NxJiep&iG&$6_ zro2jS2C0PRfQktW9^J-LNo^wbm8!pStdlX-2N21OxR~?XsX8m}z~OV?uSb4Z)&M{cC8tM((f_HbXHg07Nf6Z4W%RQ zVK%sStbpZETjw_!U0Sx}CO?dQF=m>SV-is%JJvJ;WBZv5<4LxSS!vhd432A_yPnpg zn@;0C(1pYRP5WpryE{w=TWw~dRoLL_vBGAtMO`$`j8mK$bErqU+D5jmZD9x5PV~Pc z=zb^Db&sR2=|Jj14r-ofbV|!aW;&-5hMZT^Lo{ZF3ug`IHM3ke-;=m9WEkXhKhkUG zw+CEH5;||AG3&(n{oGEMC8?-8*JCok! z4{_iAB6``$WDL)9Tj9rkvxmqOzKmn#CN90p^fLQ#6VI2mZF`yDeoNQ&Sp3858E4M% zn&Of6*FvnaD_N0Gb6wep4`;9#Zi|Te^effqk*e6@;wQ9kb?s*Edm$Q-Q(WIA2H}fI zRw-E!b_v(SzM``20`fN$x6E%YwA0)Is*mru((L7`J;uzj%h?{96I3Tf;OEx6LoOdZ z*=TnTz1$A2-&0**`WI5%sdrMk6jW{n=w|9rv$aQ6*9shh@6yGw&Fm#=#TB-rT|)J^ zmdfuKmHJ(~9eiUrC`1|e4M#?C@(p`)&0m3w{VFx%UGgZ7bNwI9w_ePQv~Nu|a{3bC zS}#ErztlcOxss3?Gc(`fe+We`ygq5kP!!;$k4!gQ?7i$Ibf{muvW{W$x` zJ9P1NdytTY_|i|1EqI3gx8hfy;)ZZ$%+Mv>Qk~iTNj3hP&WcL0nyaVBgXtc2sr6@9 zKs(nHb$cM;w6Trp9fWB!06p*pVU zgVLwEev5|Th{%s3vXveomZ2oNj|wTiA$P>|kSWb(nZR6Qg5VkP5q<0vvsYX*H^o+) zL`<z4d4rz(+ssO840r29oWF0gUh221>sH#tZ3hbihK0{8(7dIKaZa)ZLJ|>ZzLRr{e zq?7y5>|J+TG!ieF5xTMIlpHr4tKw}LGFH$t+) zX8|cJCANq%;<_j#Uh(sFUf(WI!2#~R$mY(v^X`_L!`~hbnlO|1x0N#(w;R}DWByt> zw~bC=CyupipfSmqwB5(uK+zaWW)%fxUC|g_U^|&nbQhOUF?Ir#{0jfsQL2D{@zWia zNnI%8k-(c+^kNdhOwh_HVzuar?=Cm)wl5+poqi#=MYQDa4s-{>Ezj{@uG8~^O1Xz* zxZDRNcrHgVeP)MyEuXumBndz8QgSPVkSF+rCd0uGA@5}ta|<4cv0fQmkK;rG?=Mlr zTOwk66Wm>|rCaA!cXPZ_WG|Oz0!}j$hX=Tx-YnP0Tj>URYq)=^8{~E7cV%5&?|YYl zG~~BvS5|p_?NpE2+gocFc#G@_^m<9Wq^_1c`EF=Lj1w!(SdFQ z=lxF;d5qNK-Mq=gY+Z34RwA*iAZax9$W5Op*6{m@C_H=ONp4Fj^e{0FZ(}*}4rOX4 z_e@rBCuI${lWmr);~G)*e*npt$Tc^o9Bm?U7AXv~Y*smg%;sM}Ir>loHg+Y!Wpc?J zE|BR_<`lG3WKA%nK}-#vZFA!VO(KUF+|*RUpTP<@=|`kUtQSK`9i63*gFQxpHMa6lK{8Q5|QdQci2?(l3`oV_2N7tQ7cR0~F^>kT=6w(*{rl|Lmk`%ap&K zWNJ)c0?5Do{K!7D5ry8t5Cq5L6cM^#o6PW>6#~!hX?PpYdSChj}qzF3JWBbNx6EO47udlP=iY3927 z#msXHcxOj=w@=X3e=^Ca_Y=93CJTLNTQ}dVb$^-9Xs%MYXEuvSVN;5HMzf+`68X*F zps6#3$qTgxQp;(&q!5`&~L^vgGFq5kNET^iTPx+m;s_9O3l{)>q%OJ9M>XG zx0ZWHD#-{wMbAvObEyn|GNkj+k94Fj`GflPFtzMUUdvZzsQb=LX5H9~2jDu`dR(y8 z;;gbiq5^M#i=-x>?GHAUEd!5NgIc3Kn9fjBl0?`a>1^uSzj&qvrU}g7Pds}EQcAko z+NPgvNFCkDWTz%PXS?ezwi6nZmgu6ewfAus#Dne2#HU!-q~lxq%5`EcYAt==<<{r;-FZ}!m+Tu@@d$WR z3X>4bDl;yLlpIH~?ce$(3dy(TmWgFHn~K!*GpXorqH<5pDw`K}@ke`y+UKIJ4bGB> z_h`s_+0PL)^MC)fH~V;}-!Oj?7mVFyGSJ%<B+*L=RS_(`eI(_6J`p93vJNi*YE@XXwhO)n$ zorcGE8|&3^(SRJCJG9I_rYa87B%V2e#U7$nr`oRFvmHrIEtl=q#s5HXMBZM z__H|c63Eo9xNPZa!eCaHja)v|O)2b07KLKm4|v+v@Vc5@ZrTxDuis9_<>A zTrO7E=+t2E@G-ohz6u2NS+k=(MEH9{EzpL z70f4D-&`S4;<5My*Rj~95Z!D}YS4nzr{B@1CglDI`r;e1w%N)o;^{Ju8A-bI0?>l1 zd<)--B_xpDwoPPa(3p-kEh$J}`%?Qo1XX%h|g6x zmxbigmxtB5M|HNyrUvK#7RIimJHr|J1^sp`7?3Y^4*b-7>g}yml1J=m`+e62cf57YUb(=qG;&i*B8H*TAewwtPAN2)CL5SgNJ zR84ZNrZSo30cz{~PUvR#Anu%B=n6Z~6;`CytW2hLb+pP|^e8(U5BdRp!9LN)L8a$$ z1?gmmqJu4@tC-KaJ-UYpq?&Cq_t_^FTG^b;O3uaABeh;(KI$3hYbN1u`x}MaJJZ`_ zHUmv<^9NTA<~%TKR^fYlX!;x0D^u4DF?*?yv*Wbt!*yg7_-%f_}X%^_P1+(4Rf zTyf7hMO253fIj@{mCphb+Y%s4;HjR0Kd?kZt)s#+Fs^{{m6B!E$h-5u+GFb8)rxnt`k3^ zfNzX`qA6Pg@f}-1TVLb^dyT-yE&-FS0A?NAUcoVRoDOz9-Rn%&!+zpN+X|GYp*RO` zamTh1w>X<_lZ0^9F6W3}CO+CfWL(=qerr?7>}I!23iJ5bQ~+bkD|(r1be5?_18VqM zCIMOTIYn-;w#?wImCQpigx7eSGe^NRB{Z{{H8vC`bA&hqUbhOqZl1X#Cfk6i4k<)! z&d&5)L+|k3R&qNKMzVpOPA~Kx+_{KV{B#|(`?UK3lsb=nOc(Tyj_jH1#=DsftGvf( zR{RaD#6!3;cLtem>6V&S|J!y_x7-4KPHFaw_U3^&h@&~PnIZ?87;?JqD}Pm=n4z;% zd{QR`GfBmII+aU$n~aNZp{{-?2b0$RyJoThzKOni1_&nJBs!Gr`m+2=KNauchac;G zGD^>udGuf=zxM&*oWx@`%g*{Xe=7>EHwCp7(&P<&-Zy6030XQ|PS z!fT(jS=>>WrSlgnxinf|GKPZgMCM5xz!BB zdDDEuN{zR}B`{B{;&EL6>?zjVE#|2G(~JNOEohf(Yxgmu>7n_am9{sS z#yUFIJMc+QQ1?8xqqrSoG=DcOY<)%Q#O7SxI>X@Cvt4X*ykrVeLeRi3*(t9=u2m0q@z8IOi( zj%@|L(!s2=bcsVR<_kKC6NcWqD8-!3E3Y&U20R^!=u`m`OZ z=c4NCY0Kb>$gF$Ybfo=d)`x6){Ro||wY~I5k^oQJ-ncn>bF~_;6EUG(@)<-21B*|- zTzvaneY9`XS^H3}Wi<@1SB+F zoTC!G1`G2ao3h&Mo+#zpA&YKmgy zY-WWA^+1$&NzaXCYH%YNpPC}6YbSFvJ-8f6HZ@>{>${J#%KtK!?#qU5ot)u%z>(&p zcl*kl>m=Sk&yV2}`YBv0Ke@~9$8=RZvQD^vrgwurE8_n3GrC27GuOi(=F0lB*mt3g z_-pJt|FrW0&m{?pFhhH+8yf6z{{|1-h2WvPADqJ1HP2lPI`DI0d|k=iiXed-5+rpE zfcP{*YXI=NT@^S*+5_GOTd=_hIJ(;$&G!S^nAP|ghtI=ajFz%t@3hw& z_x=L!zIViXfYaiZchTF&)aYf*b^XQris{t1ydLtn*M(`+O{DT_d8xe`UPW@PT6jIZ z5#9v$8sW|Mx_E!^Y|FfFyp8gqcTetT;@}#;00{*}D}V5eUdl*)bcSiVgi2@Gh;S+mHiuDn?QPlf|TCO zpn|tOXzLvd272p*e%`R4wO2bR%3SUwWHkj|#~?Z$g7n^npuG2v{XPYKy^ldxwyM4e zP;~judqocJC0~0-gWTxKI(a9ULvtoL>1__Kcx!?~-tyod?*H5WI{4SG8l3aH2G9H- zqGI}qqN0%%@Y%b^zAl*W7Ylm$ErUk>7}r|iMklXl_tpJ=#cmr}BZ@CU>KE-0iO6_MIP$LR5A|I&Pajb~>z%5D-mS*zGitYfrX{-AtY~3N z>qG1}3y)V1HC@+L6?6p^i(~_-YpBG!6uz)jsys;sh1C`n;ELGCHe4MJdnp$VC%s^m z{wchREr@qtGR63FnzSbGT*E&gf5bwZz^%6Dxk#GW&0cJC2W0R^)#$S%`mP&`0 zB6+xifA{CUpHS~tR)2=|)!DEQdiSk5MR-qVQ?W@440YP@j!qsfC+B5?PK+lZdN@se z3jfAGz{J_`0gjCa_z(7}`8WcmhQE-N)LD(>IftQnABrY_bT|x$z*eO? zy8i9#cL8nuDfK-%`ZWAar~0GnZx}9Sresg%PSy-HE{vyPg79ACRrms3eRW2v2`G8eSwJDT=M$mqTjNm-p&aB#k;7siJ1$At)Oe749MX=f}uA z91$}~$efFBWj1qEmWJ;mi%58!sU}3mspXL&>_1KoV75xR$VQbcayI-Bc@sXs)A2rx zt%5MUN{LS+1s;L~Bt*&Z8h(%`DvCLo8N&m7E=yF4a3=nZ<*EptkJ$X?As&qjY66af zJ@_de@F~4j#nd}hLS5lgTd#x~L#j_7Tp)wPPihVMQ%_W3ofKDMI@MIiB_Z+^sXm`o zX`K^?<7l=^s=P_ATAMs-3eL-aOcu4nq){8q*XkGJ;b?rN%Io{8pne8#m_W5M`PFZx zmfFC+C(SqNtbVF)>Fesf{-Tp}mQ*F-W03imX`Wa0VLXW!%|(69Y|Hnx>W+Yd;Fg7ZEy6u)$D7!O~Wfshhn!nwf+zjf=VSM#W$~;YAd@oWG81sUG@n+ z@f1kIcIxpxFp3XsQ{Hh+uH&WLPat9aK)?p`uBXyhtpPPX$74Uj55_?8@Rly}sJ)Hn z`n9WVKXTnyJoY2q z+DrwT2g7pI?R580UEXyg;X9hb%H@WgOOA>%p?mAnqA$%VzIM6cBC?2PE(ds6QL+H5 zlHk_@9bp@|iFR-in<#@BJgBn~w8N_-(v7etoj3T9fP4(;Ms$B^zoWKezQ-kVKWkPe!%(RzCM` zOMJg1D#i7hl1nwopXbf^p<^*3;g+-y}f9c)vZ<0avUsmc?9HFzk z82%u6)bGS=>nqp!zsn;`GPo8blP`nD@>wue?hIzhLBUjJzxI^zgG$U_NrFT4sh8M4 z#1w>$-Xk0Wm;B{kJO5WQtUAlyeregjPlBgd$}5D>M@1<9Vnm9kXtx0&j zUwbdSOk{7>@NRgcNT=H9&Gb%s{k*GQ2XCv_#+yv`ReP_KSC>q!u3iIgoL9cOHu2lB@ru?UsC4r$H?;jHrd#}gQxYK?1raxn7>;7;dhhk zsiC*~f!xZs`@8p#tmpkAqk9d+Mz0V_6RE`rFP%8x<&_1z>T-?On##VNSCH3V+NUyEv9DO-UWC>@^ehyg6c&cZgiJ+alsUkjcCYJZ_cv==BuGy&Ph`{3Hg-O(bE>5_QPg zts%FHCh|Vaqvo+uB8R-~to+lRgT30zoSyUIJdWBG=$w`^+h+|t=vmUTUU9C*aOu!( zzeOu|O{TG-OyknX1e~wNb%PP@feNxYO6mgcFlxjx%n@v1?{hV~17`mOo#B11MyIJn z|8(DSWxR*3a}LZwKd`jMY*p~Zm$aE}23rIyqY@ZJ4fM11%|f;@Bs&bVIm}QzQNzt8 z@WM@|4~n2>AaLc)b_2_xKbk}OAZzLp=GM;unVe&u>-EOzO*pF-H7W7P#a4QJfUIleV>5Wb>-Q#;We-h8jeI!gO;>{cD9fYBRCb zQ5!*4e`DrzGdokdF zs1h2YF08~YNt(!I^Q*@;gIb6VXc!u$Ur1uuYd)d5NvKD&-63fpI#qZo*tf6DQuvoS zXqz_b{pO+G%lldf_VFia6*EC`XTT3F0|(g)3My@8Q`mf?)=Y#Bt30hCOcq2T{vKTs)BsHH&Zi!=u!2`{Bb@uzD>fRc#j7 z<`Vla9Lr(0)9w$vE&W+-nz<~lBfP~V_d9FLZupFAq8%*z5E6H~q6jDsFA~q)c2C`B zj?zqSuc+hxn;O!CRih-#cPg>K#bw1wFSfXfV!sGBCb#(E8d_qXyWDznIP77qpfAbfh;tuygUBt@c{lgI;N# zx46BI>ir&n_W^(Jk__!}dCcyVE79{Tu!rS8_8i&4m%Oj-QSS%)k5|o-9B4bTUmdyH z){H# zG!6D?s4VW7OylZ{tz_)Za;r$YeJggNcDOC7F_Y^DX2;~i@KT#aB{vVX z@^bdxD*omBxPVvS8R^8I&>uLu(>QL3Oa&*Ei|fP>t{bnQE4Wh=GKPzxrM2XO@0Z8LG=xDpibG9ej1i8mfVjA*zSoHRCzAeT(j3!BLlg6xKs`6qliCM-B)kAVVtWXIQ zNpJ9woPwu4Yf7W}O-N#mk<6->o4DOz63bsrL0QwZ1<_rCKII{}cxF^k^UK((~ld?ZKn5*pN9{pE!5MEbe}bLw62s84v@lml?>PrQyca%stB3|- z_tf0S@0f_=_9yg1v#G9*l1_7(^JEj%)z9!n$*D~bu=S!=tq*$H$W8;z>}T$x2P=TC zvICXjFtn9}sp!}T@4z9d%HQG98^Sy!Cn4qm{(<$JspCls?8epYCnHTGealp%ODL&N zn3Vby9l{NLnC@V$AxDU0l*J}B*Sq9;mx)2=@Q6JQ=p*_!y;AqbZ`w?k(+x>dX+am> zNlhkYrLXQq-_nF^g5qij-tFJX5S*fusXufUHAoj#opfPULuVqlAR2iE7t~K`m1?9W z-~t~&Z!{bi{aCv5h2$BmR>jpudaHlfZ!He(MXHlpt|sB`-lYCe%>SnE9YdEjRP`kf zrh)3rzV(^?Qbl#)ku&Ij_o)2ptolw}B!mADKJRt7>gUnp&QPgw?AK5a)d-zN{Y{F( zeqQ}C-H;^2B5EYBy0%WDlI!f@8=W_Npo`Q0f6vUm?^S-bYPzawtcR!udcA6>AFAdi zhU$U0_;>umTTN5co)z%!Ce=msC0$m}*4fFENvuga*4@D=e%IgWO}d^wr^oB7`cLqR zO=Qfh)hqb_cD)+4>AyVwgqf>fnL{QK-B)qGv&M$}A5+5g<62#xYjrVF9y7B?E*+s` zi)n^|mMrIXH_Fyq`Y!s^yQ(4bx1!zL4ktgy)kjA;M%Ti9 zUcr?M+;vbhGRz1rxVuCx9f#n(tTl*j(T&zoV!FX@l& zy}l!2=uK!VNAvGSXfi9fji|>a>C&jsYPgo%S4Veu4fO!Bm`1uDVBmdqSCWz%qBLXP zy#5Ima}dwD1+4qAn+}WFOTWbbafnR3xh}3AhEi<`uWhF*YGVB_Evd4Z%WFIBQkl0f z{Mw!|4ppACJ*J>Q)i%1Y9R{a4O&1`asV6GYO(-LjZE7-- z=a>(rMH+itM^HMPx9|04drPmiYxGi9&xQ2GBj7h{n@b!U=hbcVLZL8GXKXbc&5qW! z$wpiV7kZujpTeD9gpF86AKl*;=kHY4V_+RN+R6Hg<+!lZc}<<+QH$zdt`Fb$Y@q-3))VzRUf)IXr}mMBbb;-)Eo|bW z^3H*#F+crr4p^a7aF(g;X;dcvpwC!j2E(2Hg*IaqTArzJnN88+r$kqHm-#sB>G9_= z*J34(pZ#PZJV4764Mroa5GFTUPS}i$Zlj5VGw2OR&~1*8hi*Pc$}RJ~NM@>u3g~Sr z#jK_U(7K*$i{5;NbV0^6raa5Y#a9h9goNR#i5N}&@vj!q~UI*H!44~o@Ms9A@hRvj;Xu)pHU91mAI76ri|9D#kA zr!)Xv$0Rf%n?-k2wB4Mbzl|cLCMF(}x8e`Gha|}9Vldr!M>`m$DHPJ(XZ4L+kI)JQ8Fr~tp&Dq7)O`o%q>3%|yzq;DqYERs0VL2gM!e=CuIMh zp{DvvRHe&qCwtLt_a)P@4Q zIVQjHUds}mVlLe)Ig!q3x;I0Pq8o4P)sU6EHnN~MQC6W_YUO_;=aWix*pDaQc?Uhu z>ka{x-IHDnI`L#)TsV`|-e`KV-CljV$v!YJgS{G>G!CqJW`u7V4cd;LcK2EUBI zfNp+)pNvT)Dg2v$svyeG6qNMy1+D!u`1NZAzxvIBp?(*5j_#ywwGQ(5ErMKrc_x>B%6*so z_wowd#w&j=?AAOl3X~%bY}qs4$b&%~`76I~L?(7Ne-^pSJ>}P=dS~>9$^zs|74xsi zBK`}R&%XeYvI>5rjr__l4qKN@eDsrxmwq1cz^^MF`TfNee-hhNanv8f)>Z8A8;O7Y znqsBjM$GZ2iT?gR(ZPQL3;06xfb|>aFA|&mKH`MmSRD3iiNF0H#Q<)rGOObozo658 z250^BA~pO=1HXy*#qTZtVgEz^0I}U~D5m?lMSDL=l!cr5&f6ls_f|9ca4{YAe9?&v zs}UYPVlT5;OP72=J{Gr8#zv%;UwcVpMlX}h=OrgeQpu9?m@FWtkulkb%+HcCz05{N zX>M7E|Mw$#;8&SZP8A>I7_vEsiC^SMG6v?0MqpG`|bT!oNLceSBnkiFD1G1(${X z{EJL#ccQwQhpTuPPUW6rqwPrgWMfoUHJFl7NvyEt#b34x`s^Q2U*+Ulmx`3Exb6W+ z&Lwlkej3pRJT z&_pFSslkk)l<7$=&=@qljQPu? zAV1rhH2NXlpp#U?C-h5whHRG4xQKF_!1U4g4RxG3p=bV2$+TN9Gb{8lre`Q>x0q;N zJ(H2TP*E2?&^7tjH{kn^^h&FZpwuJ+gjY84p5UpAduXQQb{ z=CRHW7Bbc>)%zQn_Yy~g5!0$d%r$$VC z@P@=Fs^WsNB&B98h`y>F>Zuu~v-!vLpN_Q(-vj23(I5Mb3dZQAV3%?%t?F|7fpHiffQ)fBDjn1k|> zj`|YMe-qx}HlM*KI}-MF1Pnkw{?*U!#N&L|)}#x}h3+dYDbY#oaGT!N!edtqEiJX2 zZAnM?2U#Br>|DDT9$^4HLQQytoUja8!ODtLLH}&-@#!9hsreh7&p3P8G>6wMXnUBn zypm+#JUMM4-hB-)wEpZf4Mt=!TD!%hqc6sLGnscg2^?q&8lSZ$7hP*g&fa)T^Gp=6*EJ8~9YGp;KxM7oCo3|1Jrf%Xqb@rFq7t^vo?xciYTNu~n%> zOMwLDWAB`Nw&nRu+ksY1qbJzO?KPbC@695vEv@m|6tyAzldqrBIbC9e{cq;Ewol$y&AfkHw-TaFpf15psBI*&_b5v2B*SxO-_5kk6T0Q#r1HtvEYIsGl9Oq=u7jSp5P5Lf}YYdJm(vK&T$ywSc+rw@j1suyLFLI za4jCq+2}1dDDG_An)!SqCv0>6 zLN^{Yfunsk%-Letx!Jgy2JsEF;20Ai*XirF!Yl6P84lT$aH1dhG%oR4p4$H-=}zExsJ=gd&peW7u~gcN zLS-!~WXV!e)=HvOmXhp}ea$Xg+4r5SmFyvDBbBK5AqokFvJ~=tX6FC?`oF%f`<>^R z<<2~J?mhRM&-t8lpL0b6_;PJNwQ})vt?@Oi`R}+;auaN`2oG90jJwL%agXEiSHMBQC*+AH$Eswuq3L zAH1R;yon#&OCRjaCVDNs2czr@YrK5S+U9)||1~iEzhsg!laF;tdbun&(^%%?S?(eY z(;MyInT*n(hl~B1kzSF!Z~rE2vvsoLEKMIs#za|@f$rH+?v+=>EHw0tPhto@VlJ*I z)~r@k3uaq4X^L(6d^FG)m~Moxl{0Kjd^lQ0elCoE*80D)(2tNQ`{Q1sMdrrKc{oSK zi!lL5iK-hAzX-u<39B0DZ#t&zf_QB_kB@TjrJM{OLhdKQuexE+cJr2cd8e~sS>GAC z7cil3_eA$bb@)9?C3&LK)>eiKM(n2O102R(_Mb`$;$}aDqg^q+GpS1xX)JF>C;R(A zpNC>xPr&@2LOb~YZ+kUP%W`FvXn_yn7n83<@Eu`s-NJgS#Oi7wvaGJy$8uP*g|PN> z#~%jQvBd76@stuNQYqRJJS|e>8R%a9D0Y4waf(aCTK^HWOs-RImO&;P?dUK|?(<*@ zPWh&I42`M>&8oM2K0U+h;t4z=ORTQ*l`I55VB`KNE5X0Knm5qI9t>|zYJ}G$jbtpT z2Zyc9t9iTCwzGyTkIyV_{=4;%(u#Et8udrpLm{GM3yQZw(8@r`Tb| zWO{D{Wu1oYw-%Nw`>W4YtmsodX&x5A0=zS65av%>veyQ|cs~yNTchp0pdx$hjc{Y| zPWVAEg(f;7tYw=+&it+NUM&g^S|L0`mi<^v+Nt0|u+_08;pM@2v2HU(Q>_oy1^a?! z!TI1r@m1?&wEsH1Dfm(D*2CfLvTPNWajU#l8efooYe2A{pY>}#*!kh_!8rPDkMQH5 z6Tefpu%Gy>5mq%{q4r~ZShraV;Njq4s%r2@>egUyn89lN#@YaztjPCGP?^?UDpl5s z=k0=usaZia>kU{%C#WrJew|crS>E~wBUzCjr8Wio_`Qy&&IIREKL+PgBlva8hB?B6 z;a%Z0I(Sc+^Sgx)S`i?BxIsp+KZ67OXHa-~@#_Yg`Oo&y^p9BS?{unZ5b+@1oLa;x z{UL0EDVJ%L&Ph!USEODF*QN4>tHL;36rKvF$VE0bbxk-yS!C7q@58Udqq6vCxYs{n z_b>^^`}|ER75{UFrw}<~r6>^7Synp$vOPC|P z+4?mn!=2W#`7+oLZqTADIt(*rRW1udzF2eMHB@qnwd4;~QNe@|TJK8=OgMysK&F7Gd z@p9$A30vqPvSmbaAX%Ag6VdWb^1ZbI-%k!F9Yu9MDvwI>phQv|$}v)&zeDa?SVrF( z?o>jqg`H502FY7;F|>+DCa>d6w}?0J58cGS^lI`5FVS7e)FgNEuF_jRwN6RCq!%C3 zL|Mt!I({g*2MUsvUGsgC#4|A@-VpuVFnLx^pC|D;UY7k}K524J1WHL!%+=zW!F~Al zIoUi%;WdZiSwTP|Jfw6r`WM7AWq6nzEQzNFo#8kSk|x=#7N21)=4(lnDtrrX$_zCH zZ~r6gycKM)4`QQCeCrZYXjwc={;cl7SM0IR;x}PG1K4KMg7t8uB{DjUvYJ3Q>=3@_gfWlS5i_8P>W!FGD0?qwN^FS2D#ZM_VYwA zL`$~hqp2(Yv~u!^BCau6AH2#})7t*GlJh}#*%o`^61S7@?lqi>CNkPJvo^--{=eye zyG!e>_ONH9xYq^2EqX?ZXZW~i+24b$B6Zg#d*rhDNe+wef}QeFU6mXROIy>jac~Pp z#*^0X=ovN*7Ru`URX9*z9v^%RFB%ul5@|Xlcv#=e6_yg2n%C--xsxx#yUDdjS-mZj zo#Ei*a5x#>G$T2t>x@GWIP@-1t5XE+Dbd8y+cIX*j??^sW{u$o~$ zKkHdqSYfs=57ZRruM9_Hk&I5Zs^iPBr}JNDU0a#f`9H|*by5WEwc)VffpALjbhwZd z`XJ~{eoiw^*2_+PFl=KCz8IVhpAUACcB_$O&)C{HRp4I8L!#fjR%`S5Y8f>a9rc4ZuvwI)TS@OoLT?;tmFhV#j&&yB`| zRt@*=>`Ph@U)$k z9%0RJVAu?PF^F`T6D}j+R)&9stI4;Sq)(^tu(f*khu4r(d!ZO}Fl#zkd+XWM9l_J7 z62bF06g^W<1|w4Sg2^Q8yQ$hikJRHqWBJ1yrJlC!6tqsww07#w;H}ijpiAoapbZ?R zp}gVMTvs7gB&dYFP$y*#ywp=ci&PEkvECCD4ln9s2feeSqJXo@{#82pHPt*ho9ZAM zxKU6bRUo)O{K9^xat87`V%baz?Xr?Dg&i7b9PxH5Rynx;4K zO8%Qzhq*|L|F4DUBqcOkR7UYawI7!&r=!kch%*9tSRE|siY2B^{i}8 zokY?MCC3&eSI}rOlEq?cMqp|+lZ)(8aYDr~!|sc#B-QZJn#9*9J>win4_eV1G^GY~ z*;+KA8gV0<(~G`8A&Tv8`rdK+><6@~*7Uu5;;rd@(1l5SBaPyb@Rk|r(lD1AFqk%M zobm9Q_3@eXccMkViT9*QrF2hOLmqYf_V{nn6vxxI#XpHM-ORVL982M2%!!{e=8B|f zkldbeNAkeMD5;*2J(2Y!DUs1Gxh7*~d?e!w@oArnQ(G)Htxr5VqkcRyqe#3UBd<8N z-0|3qYvaDYx5~H&`{K^{`Hbu1S2M1Pn`c}dcgV;ex5%jIbBnlPM%TDbMi=W=Js01d zaetgMBS&=R;yDORHW^q7V_dux{hl#6im*Fw$ygtk&iE#-k?}+PSjKO0Nza)heMR(5 z`ub?ByuGc`)uM*!no);z@o1Q=Fe@@L*Wfs)p0m;S>8mj^OGew%RWLMb+SY-NG_k*5 zw3pxSaM~KI>7%mA`~sEPDC5j~(W~iE(bHn$8enxchldQs*jN!Yf~2r_;0kS{vGIFR zZ&<`DB6w=Wm@BNS$MF(tv)(hm*HIp0xmRY9SB$&cUoXnc@%tWoZa*(rP8R>YJYpp< zGxEjH(zF}Xv|C0Qe9M2buJ)^EHw%6jYy5zF9gWA!M>m)i)>72=i>#qXonJam#l_-W z;&XGdhjOsOuHaMpE1m|wSil~5pDjJdvyP13X7vq?U-A4k;cHdkEEQRL)jd;PQ9e(K zFe<|y&5eKa7Z21H$lOXuoOoNYKzpOv7$+Y@Q=@OAe%7yT&l2k*qg`9pSXB8EV%fd|7wE*&9FEaGp9Q;t#k!ugyC5zA`N$c)#8!UFwem;9rSid>?uAF*?V1~4 zky#;GXYt$5v0g8a_K1Ai&)z)9iupaB%f4K|f}A48y$kEJCX2NsD>y$ZwW#yU;F(s4 zPOzMcdplj@yW@{>X->zt;&~RryDW`)`7}Ofa}0rj$yLhjagU_3xYL)|G2@}CYmDFn z@#V=`?9^d~ zK8?P`n)p(j+(+^jj11cI@HLL=2esr+EgjX7Med~}L+sP9BIP$ijc1Fl9~|Xl+hs}G zr!OY0v4?wEL1$R>EYzfqQlKI=ko{?|Fl(@WSRB zVcnG)dgwz?xC(HJ*F}$xH|oBy{UUzKxew`aIgHA^>AlhN^h((1bol2SSm;Ma_-5R! z@2qgQ18?lhXor1E(=&|hsU*e1s9pMdzS+z5?2339&7q(5Ft1BQebWb`M(Ht_01YrR zO3PSPE~=e=F=~bx&K3oiU#R5iUSsz`$H&_*}G zqw|m+H>W2@g`HCmn%W_~I~o(=z(kKn<6y8oqBr#8Ci*_#CYE|KPA$qfMe-S4H9yqoSfXszg6H|A**>=w~&45xve2-P$i}6V31& z7mDNi0lt(n{tIZahxwpO!#M7YvKd2n8XGV0NiT%$o-i72hQbshfo_cUioSh6+7k^_ zV{?+ALG+Obk>zUM2oL@=nq#DXX4Hy2jP@CcKgE|t->L0OUi|OfZGU_%EHGc3jfA_L zlsKuZGRnGniU*-xVVpgEB8shWeJaWWxup0ltUq4Q^}zv@Tz5G?m|!UHu>3HKn}u%SoU`$^f#ci(k>qu{X>f=o1M4C4DmZDC5|$=nhkUr^!c!|A?^&>84!<%C&shlh4EH*OZc+y zvBr7HxOP%BE}G*1K?^FByg&o0MH6}?c^-fCxug`msBH4M44su7uS_#4O*1NC zor|~r-k`DTy2!u?K5CMQ-c%92s-8nIL*6Z37)%$ z*gVDAE(O>)*RZ29Wbrwf43`J6Yw(Bq|6$8yhx5qR18K<{-aw}fgQED1dDve^t$DxM zYW45QR65t%w#$NJ7?Wvw?q#gLNG70@$?D*LIFg%v{)F%U3rx!G*u4Abt-mCH$Ps+V zv0r3C`T=M1+u%Ld&$JHShsihA$Cb-4Ne7FATymb@AUDp9R>{3eo}3)4!yGcF7YcgO zdV2&fvJ{&`3SMEg%ZVDuT^6KR-KW^0S&}nBKDmYK(xiJp5@tHlFSZzVk|6S^M20~ zJx8O@O`9*t7g`O|u@Np}ODI@p`H0^V6WbdX@lClhYFkC%E}0h(id9%){edx}Pu)mBBH_9?kB&M5eQ&$yLEd zJ!LAiu#es_SdSVl56EY7zwcKvpnh>uD9q-Z3-QI^yb>qbp?LYid`TJp+sb-Gh45O} zoyTB3n3*qx&A$y=`J4R8LA(@a@rST%d_rt*HVEI9?wdtEfb-V%{+AV=HTc%OPbF2{ zqY=dMjWAEr&GWT&UTwXhg0{H_FZ1@0jS+T}ooGZ-);f}9!r@72-;41#-^>aMWU>Ay zEEu1Wt0YHweR7v)tmyiRETRYW#v8&w2JD;gzbnU)NW|-`hFLBAT<)eV+I$@gd!90$ zb^f;e&%KlP!`8`Sxu+KB?X&do1z4zyWxHGfE%;hbJj}Yfl9hFTSUIR}&C6%8N1kDA zKN-%14ve*bP*5;ztu*xc37Ftx!E?4P!>1t#O~rh)2wqZJLK528_fA-yom}0D0CnZ_ ze;G#Eg$?~KOMQm26#6hH*kQHDgJDO=*t2ZzV&T0k@-kr%-XA2^-@L^dn-zWP3O$>} zGG5OD-oWae4rA-<)9Vn$=OK#Ev!gR@<+4g4HgeH$Bpd#lu&q@J#^VMoPdyl}f$6PD z-57oZ3!EGN8;%SA3R|+BONIJC%KKxjZ?^pvJ3nES7h+F83|SN(5;k-Fn<5B?rTT_r zQbWUeq6U_wnuJ?YkA%Ob3Wph~{Hd&|;;E}rWknrS$A_sKo_EbboP@97ii_ND7VH0g zNa&taw^TOkjz5rEntBooriO@$YN-OL%HdJ9ElWMBln=j1m4Qg!B|hUevBx*0-omOG znYtr2K6Ptqf_>wBpW^dWtHsSu-6tlwnh1?2#9`D;^-4W2D&twqo98faYFg2uYASE4 zWa>t>6-^a%Qzmhc2#PnbI3__i>eTI!ed4fm;MPwH9Q=fY#D z)?%IqIR38t4ijnpdMb@YR5rLCip)C zE<01dnHn|<$Ak^-ds%O48-4&k`P|leui;ma>h-Xtk6^PigGJ%AU>1hRdsf9=8LkdK z4L{L~cfxLeg8poW->-v9;izDfvxY z42x`#-CH_i2}l!h`JwGd0zR_5wa@Z4FhT1E$0;oMb@FK}!QEn#YWJeej( z%2c^hX2l=CM%E>t#JiK7aFW9`jpNCc$x&-s{3ZwF-uP|%UrKhx&-&gd`91EMoRV?! zUn{^}7SDhO_mj({AXZicy9=^?HK+ihn(f&R9`g66n-b>X>{aRVP_ zWj)N|Dj!#b{gzWoiE${b&byP7{D`OGys+a?rpr9RNcpQji>u4V+srBfeMM^b!69tr zUbT6n9(GYeKmm zl>6|$WFy3VWl|z}&zqZNh1MyeK*osz86gK%Kks=6tiG2x!V%7&;4NonH2<0|_d66! zeoC1W^Ray|CX1{@@~XFcJGR5$@l0OGwegwwXPV~eZ?hI&iAG1waJ-wawOX-tTKHZ! zn#d9xA7#U|`70WcK8*eI2kY`bwp8|La&)r{DK|xx*kF0(H~uI6DenGKvG8lse_Ls4 ze{@}X7rXIC=+VCD2{umQbi#fMFp+}vIcuN(r>b>(2+-k{z*R-ig#|AF);=}qpo9(VmyO!i&rQJ!Lim8p70cS5x8 zNOz5{O~2{fS3FM*Q3VyS-AlNpT>8g!?ezEQ*4C=(mHr|$jw$Esh?wipmJxqB=Ji>&GUg>dS76yq~ zcq^lU6=G|MVW@7~z_z7(3{Ah5F*DsfV?p})jN$2~8O@bP(rq(}q zG7_{&f2XeP8Qs%gXY@#a;rr^0&gqpI?bEA78LY~9JN=R8S|EGDY@f$uG)oW8D4Onj z@oakF#h=n6FYZjwy7*7}Lv?0GgdghEhF-Lht>U^ z=lfLj!k5}=e|mIAhBuHuJwh$h)b>%jj5l7|J9^0bsj3$=@~(QNe^S$7?>r56xH`Qh zx<0)|&s(IQ%@Xaf#=G93KW2-rhaOxnr^9uu;XByE_ptm+=&Mzu8qt$bf~VQo4We4C z`9^SoR?g^!mEI@1$U41}RePIUKKWRr1#vw}8*h(cS2TovHH+Ud&W2+xb%&b09RKJ@ zBKqq_=yXX4b}cfzw(T$ zNdBd4t}l6VkMm<)OZP3$e^Vv+BP^}n+$_Cwe80a0U-Ro<9bDu~zJ_NgN7#*a(lGc| zy<@GP)!FrR{nAQevCCU;z9QYb4qdx34_Z53zfOEyovpytBP<~fyQFyRI>Bfj=eK$N zy3_CLhr?+pU0AgBd0MJqmsel`*GvAxAIKXn3+|)kl*1u-DBQ-YHb1xy4>sn-%Ltp; zwxOYnp{=Y`zNW!^rjB{MIvuV5QZpG!^XV9t!|?Iw9<_k<&{ z+Pko*8`{=qEkDPr*oo(GGA(J7$iQEd{ya*n1KTFM&2(bzf@9} z{!m?cM2uxAsL1VX^_=*zaP@c6U)jb2?mee*Y#kh!#d;M|xcse)_I7 zgO-q*`bv4IO(~d7LFX59ZPnz%q!9){|75QFPD|GLznvEHYqBQEFdnnREbdCS(`~+` zv22hhYYClmlB2_tdC6dTp@-2;#wPpJb>2C7`L6F3)A%qnqO{&yK6uRNeKe>kw{uJA z!;qjvFh3|@WaSMu8>3$UbDcjD#n`=jiFr8XeCEBYdBxOl7gouy3kk^W}qH z<=74*?ihTdS9VC8YGMjBK+wB9n4OWSC z-z0Wo6YK6%M^`FKmDw!5*{MmXnX*w$b7V|vhwq2Q;_vfqN9sor7<)wJ|D5{7-*%tQ zh*-#xTArn#=!=4><5}*_k|j%?EZMF82l`C?YxTbaawGgAH^PA|HwS(=a#7 z^UA%ciCF?Ux4xEnYenjv)S}e<)UwoaIlETLpNQ z-uhF|`_*jpmDy++e$EW@!@K5^5#;(9ERH#5o7Gr8p9LpL@KffnLvX#%jfIJz0| zRw&v^CTt)tHn1h+PES514>lV83ytA1$qbn4a+cgy8vXCAyc0X9CaT3?i-9Mw@e~SIQ6<+;)oCo(ZBi=^?Ie`DU8|Qil4E-xU z(9dy&mn(~LK_}zaPQ$aE%?GfYk8!iI3;*#uSo=n-)>(Xpqv7}cBFt>Q!ajVPeQ7xD z`6Qb}GkBF2!urS1dIm-rJTMv2^ZbOh`3oP3j)+0rMpIftV|s^IrZeBlvr$ud3ED&z zc!8_(-#o<Ecw=vCiaDQ`sG(!E(5{i65NJ)%z>+i}TDU7E-GTApw#x?~)R zHYlqyc1N?sCCG0Oy_s=Ayup81`d3>$B~SEhx`6vsiF&19jwYr%icIXqKlWO5NL@!9 z+ny0cYcdW*b24^DQ#1BN3)J&LI!m-6ojaPBzLh8aR?nU%dNiFQDq?$e`eyORw>uJ@O#dDoOGnX3+U!|gu>ZWBII4f? zO+~g*)PR5L_4q3Oq?`B!3-K*IqNg~h|OmneJZ<9x-D4q84q>=2fgW|Dt&G(Wo+U@&EHlyIK_zO(5Z`i$?u{ky;V|||u!T3PN;k8hXZ!tgq=ksrJ zLH-TxI2Zo~X*ic0l-K76cJU6GHRPO4{t793#K+}DD9c|_)cS_` ztcaI~zakg(`*I}B9ws_)uKbU;dkk1 z+roVPh`IY(=*$r||Mp}+yd!B#Pj4N|BSLa?B}uv`*^=IVU$^*2?3Pbu5LxZ>x@5HT zSG(?DYzffhh9HoE=m2zJ9$TO#$#Xv(A+Kv8)k%uQ0jcLHDv?~ye#k^iu7g+Pc1_OY zD$?aFPuEdC`QPG;{9gaCM1D*1cmt*4IY|R6uC$ALC&S{7FsE)TiGj&_GHXjb%^RMQ ze2$H{D((Y^YUho$Oy@WsghxwuA0y^{q|m*g`Z@o%F+$eLBkO&_mYt)9feGq@@bpGN6M(b=o)`5J#t(7Nu zg71$Gu|p5TMgD+i{FXi?YU%gr*Yr^f{?-vSre$(z29)Y(arZjPQ|?N(#;mLZAmO25St?#=pri#6Oo%1;vA zN$O-GAbCm9%Pt`xuR}*#v!dHTKl;kQHq!UmV#gLmDIWYh=})5q>21+H>AkjxNV~t% z|H)=3-pDn3peu6Fz(zKu=g1Z?FFjrMg?HKM{Tv;cK1!xto?g!m-xn1UiB=fOa~E9a zMhHIe+zNOW&>8lrTbgvuSg#Pj_U z)T(yeijTPqUeT*Q*Trwi=N()T4bpxS_^2nu<&<_&uXr`y%kikbn1*`R{ce-oEOz<| z>oH`FzE5)MJ4K>DlbX><42(a;^!=H<7(p2E$R4tqQqedtKVQy!ds))Z_t&HUB|Y?` zUScPD>a#8MwP$2Gek9th@6ixsH)|7TNjk^Z7}4327vtQnzbeUU?motcy;}^&A9C$q z85c}SWAi_OxAs{4s+<}!=!-o#W~Too-eEIB{P({@p>6< z=3x{MPG*w%Q{%=yw@8-qrhi3p?2121{_qT^A=w!uR64l^Vw)5GnLEhJ@0?vcKmqF| zm5w*c`n_D#`3fuLe2$fT6w;iqaf(_$rZS7}1-|E3pu(M@!hK=$k{Mg1LCQ)A)O5`#hZ|b(YUFad_vlUzV_WHoz>t4~EhihsycVHHdg)WA@Aiw#~m* zPB|wB%zya5NzgXDB6uszYIT^bK_4roba72bIbymxZ=k$7<5~NQ`4qPBNBo8>dybDR zPuM2R%StIopUrEv?i<4r_7%Fcy)`Vy=g~mSY^$&cZ(9*4Lxu1)_DpmBlGo|PE$F9u)Go$kaMd-&>(EU&)N2p-?9~^bhofvFetneh7(z(<}~EzAl>{}@SW}6;P>EX z7|TKW`d)uOSgm}m|8qoTybbT^MAL6YhksN2#&CYr#o;x2e^P!=oR_V6O)yhg65ilf7u1Rsocok3TWQHR#W1(i;?2CZMk1N(hj)83 z*Yi|e&ii^Hd=zWBqPI~Eg7gHR>63h#kFi`zhmZ28R_9Z#7M65IHTG%^{~zT^EzU;G z&R6?y*gQDGUwgq-S@}B)@S&E&jDE&hFS|=CpI#QlP}5s4;qHaQ*8H>mc+RGW{q>7U zylInJM1%COm)X3P9M6Z*oEu;HHcaL+ylhYL-FDF*-eyCMbX^}D=Ju|5(RGc(*=k*@ ze?g3RcDw5@xB~7_?vmHHE6;FSJ*smMg>QMfxqiX7j-2Gz%@$5iW#_^BSA9EWb(5`$ zMZK0)w$taMYW#)$y;-k&PlQHSKI5mu_4@V(DB2e9WViPHH{>`BZ{(YO2s66@pJESJ zj&jZ%7T{_I_>_Fortn&y1G25w`c2BVWP& zK7=mL(C;R?>Rsz7^u#n&g_ zL&Z+vuv{fRrI@Fy;jgN6~-nUBEBn*}zBKQYkh788C7>RK)2^zQ7F z*M;FWhgjiHV6fNI+RtmB%oV_2gMGJ`WpkkSFw7f!$DA-0hCR%RTK!<#?IC3iM2J}L zUF)|_{*+O~N~F-Zagew%-cNtXcqeFE3!I%+$@HMBOe1e=0Xd1xRPCMrDlcRcIZmE} zLsn$56qcprTGl~MF)G&RvW9zQnte%@NO9bnyOYZy?;+o4B0}#kv*KZ^4Q>|Uw=gJb zZJs=FUo&dwko^1b6f4-oWR2 zjeK%U`o^**r_fHOT;l#WjX#q&@i!XD$)s2OpZd>X4WCQqv2o_H zq-L;c#=&BS!B_hwbOIjszVOvv?5U2)Yp~U3New)@JCc@cs;==@be6?zuUTxVk61Ea z%Jy)8esU@~!md2Yi+)Db!EY>~o$T2So@fzEXgr-}fM3?euX!$hASn~yn-sBzj+~9j zeb%&i*srY~m!V%(6`@dJ^sM>$0T1=6G{9a6`ITT};KtSiz;@VHlsovCv10 z7oEZvJ3TsY|JCB-OT|s%M)-*R*dDXvtaR4XxbuI)Z~kDZ|BfI3t3193d1*7_!k5MO zM}u)EJ7W93#G-GFXW16s(?$IMo348%UTfW{jnS>@$>p>B=_1iT745#BuDnJh>g=c) z&ihlW{7P(_d@(D5^`AZdAi4owR7B>ga`Csgu$x5Ie<<#Ep1MY>W1!D1anoPH*L)tj z@Iuttwzcnd*-7`uo$zLRr_YJCI4o1 zpsDAKb0+2K!tLXm_3j(>@|$dPB)y}IqzjIE=K89$eBR1>{O1z;p&&*>5$jjn&)O}T zoHde8#P?s?#v<(U89`;@7FOQsfonO~_mNi88e|0a*7w@6lG_+z9fKzvZ!PQ6aPhmN zKLKqfL;<|Sdl{fWLwB0QF@+c8^okY~Njn|6CTVk!! z57e_v_LJ3C4quNox5oLOh|pV$m9h3xgx)IaSZ#<;${Tq#Ia`2l@L~FNCCt7@#J82_ zeR(igB}3CJ+?S!^dEX$-UQ5Q|#7qs|B=7r?;wqrEA-Mo%Jx&8nR@Gn}$dF3xrx4*liH9^JF9fn%(58uYl8!aw% zu_yW%k}X506&z1F?+PUsP5)|OmUR6Wv9F%i_SJ$4;p0IW z+Eg8$n>LMz5k(fr&mQ@w#6_Wg~PL1PdsbQ&>W)N zE;A?pEko*0*u0yPl^DXAyh}0Mj$M=N6HTt2lhg7A9j1MJE8Eusaio2Mk8y`SVPSp) zwcCx!yi1<3AF!D>;RAhyPdXR+H^*pLgz3Bv5B2l-zhG;8!N`elX9Ic9E(YC=qF0Tk z7mc!pMr9McCaV`K6YQITXEmKgJKg*}Mj1#7^ued<5){X`Dq*A-7H3<@Xsu%;H;cEa z>swLz8?dsMksMQkV(KfXzFS~{`3C|b7n!Y zVWlIPeZ@sQCf~;cVgvHZ020S{@T6QLIv^A$@lV`H=@0XpAR6Nxvq3*`PtD>&TA;8D z!H;O4s`yqf#BYg08-wXF4rgORJlXfzA^_ggVzYQ@rZ{VqHXLd@z#P+C8xC=-iz3$x z9@bM>Tn+qxMtMnFzX&C7L@%f#tHh(C4jzohDl@!;S@Dyi8=muyp2Y#nTxYVTQXLNe zgg4h9exIl4U0$M&@gPS>ID3Q$j(43g(K9Y}WSwXG!Sz4*`z}7>OEu5PNn9&)0L5Pdh!Tc4p_7pZ&GrQEHv#8PZYuA`gXDpvC*5fc~T z$_JD$eflsy?c8HpW4|Zg8n23%dGcxTPuk$P_KIL!S6yPkd;-%t$YYj^=lcPkvS(n_ zjjs)>>!00wHx%s`y4WwyJuGJa zXflw0V5sd#``(iGe*ny?pX-L$PI2w@cn>z^Vfx^2$=h(Lo;Wjo>49&%?;?JMFMQrf z(}cZY8D5tB1+zKZ-mFMaPCacFp}QbH(r_a=eHPZ9mN&!w*7n> zr{hg9uJ4kI@vh_$9dm^`C%d*U20?GW!Tyl@F+7B`9h(kU8|9kr>S*D&w}Jfi!A_X# zoQ*hyhhX`cWv}wFHXDOI&?c!PhNLwP!2l5@qePnwv+azdkm-TE+a0pX_HtUAozc2i z*;i6c4gK%y=mfuHA^mz0Pm9&gZKu%Hr(W{tEc0t-Yq43-yHQ$nNPNh4H;wpn`&J}N zpoxq9(%JO%kvtT=p@ALL)5E@DH0;^@2_Hcl*U{@&sdtWgN4m$WuB*=zR6Cw87r_+Q z4E1*Ucne*~tZqp~TG91J;otho|BRts#?bz_FOBU@Z@smC_beaB6Z+5taL;1Sle-#r z|D)c!0n>4{QM4#-5zp6$XOLxcT+2_PFTPF!HgMik{2x!iN}tekYN+cO+Wbp!*w@4n zx2ENH@?3A|fxVLF*;b8sw3_nQwqfTCj63)Z&9qr_zpE7+rfYJL4R*-0{Yv)!D9^%I zP}Pm(@hWv}xMY_thN7-?-bSm>uVH&Fr~NI!g`FsW!bsb9X^!vE0OzsM=E=pd+}ep7 z@L@N|+_H^^xtoo2lwEd~hb+>jiMJoH_hS1q_*~M-m%cBxe&V|7w!^EspT7dGMn$o78Q-;Df|=EIBlIXR8ge8~mlA%m?b&V;w_O03(n zM)wI8;NR@gwE9z+JK2-Bjr5_Sv_|lojW^=w8!J3Wn0B?2U;U;7p7@AX+2ixK+Ds-R z&sPpVpp^R1YsiB{ zO-Hc5xA7`2b=Fk;gUMQAQt~-|&$sq%(9`!Ho2+L$-&(e_`A3)GLvMvB{Rsunf)#fotuh}Rt5~ocI`yTp z+4Wz;Lp}?x#RgbPg@dk|dd0e}q_(Jm2%RiAtELP;%V|de9xXy3v2Fycs)qnv% z3+;UxB3xO$rCfUtrr^D>wleg=$02MlLg-q0{x*1rtsH;O{i=GF`~99fpmBwqR|xm; zAr?h7*2d$Ix+mzk75&x{p1mM!D=+KgCY;0DFahsyejXTLmS7@$ZE|vq|M!sSrlZ>U z7x>s8aIs%}|C3Gh53MoAoy>uCaut3_4)y0|`{ePfbHNU;v<+p+&0rH{z@W0YM^5+7 z2a_w}+=o1QDJ-huFu!}~wguTZ_px~@d%_o?b?q>(-m-T9Mphp+zd`qHuC!I_YvRk^ z^tq$E_6V{=sj_N~5CV6e)pi0>_bXj^J0xstaO6^^l3zs59TJt7iKhK3Z^|!p*FE;_ zgq-aZF}D@s_6gqIhrxHrBzkpk^}MQ{dfxcc>Z&U;qJjFJmy6{!T)mdo$7mxniX5i& z_bv6z-CE(c3#)?zhQ<_pld7Ov^+esALX z$ql34P44pvjO<%HJ-kErZ>Rn-&YMa1{t&Xb0NOa`628_7zSe@b|24XLE6>v0_m`8g zV&+y^OZuyzk&M2XS%BYwB=&&{W}=Y8*$l%lVS7U;UlY0Ur26t38QF}#KaJpDlf@YR z>u~?~$tsi5VkPy1hFZ6iKGMybXbY`<0p|FqzFG*6Hn&lkHg^AY-B}~`qC3fBfmbkJ z{Nz|D-cVz&wI_SgSjBYHg5PV|Q!I=Btp0PxQ~wWJ@jWfk-2UQ@r%1#zu&c8;1Xn{1 z3u84_;qQ7%G+=#isfjWDn)~$d^!-VYp?>|~q@hg8mDEuI2K*3T*~3;QdKCY!zU|9F zL2sx~GEnTwI8hH1@FJ%3t4;CC$H`YT9(FvDteDNewn%F(k^^j>`%H#TzU%lXktXku zL9blL{j-V2rf3%;DqIJm|5y4SV1dMg6;|sO+$5FFc=WbuA?PFzwn%7~Qe&$`Qw_PlU^gy4RYJ2u_ zau?+HR->S}9$lIRTGPm?V-(f)o=f?jFE|p%a;6=Wr{JeBpIm1pZSPl##5;WFtBBvT zy78#+`nYqL*UAz1S|y@r{AO4p?&F-{VgC3nIoNsziIp8vae3R@!t0_ayeIlAtQ4IM zpNtY~Wn2}Oimwmvlmj7Wd_#CuoI4EdzdZUUxS*Vk&IbFUbg(5l6U>SJ2nI#lgVxcC zpjR}~y5n7}gxoCH9K90kjoQeUFi^gOsloDSr7YxM1Z|@4f~NAvJ@5Rc(G06CPnAn< zPEa}8faS3xNJS@-6ELzLqkj^a1+X}d$WDGphRHL~=B&x5@%L+dM;`Pb0C9dcwH;N3n77dQ_e$PinVh^aaml#TZXR$#IE?b@IQy#6T|LEU&7 z9AK(zCOT&_+kXNN`9uigVmjeEaa6ws_lVZc$3Ji#A3_fK*R#@DGU78l>VF1dyw5Xj zPcA^bk6Y>N2>X8zo&9k9El>R3B#QqvZm%E_ijX!{g9pgjB4qGg$s5LSYrd)HjO|J+ zodU@(SVsTDEc%-6wvq0)Jh`1-RDhP2X=^+{>w8oTLQ`X>Gac<6T<1x2m8mqDiS)Cv zbeF+o#@lR?x9F1n$h7|KyrHzKAvCQ~v_kRpWUe)(lb&pwnY5x6eoZFVdHE%c=sP;q z2Q;CH&KODu8{pZ7@OVv7-gD*$r0@GA<~*#ZVPwxhxrf>t8kMN9{zNUqx2@=>G<1 zee7=q-`l5{w%h1WdxOk;iEC(W%j}ye;$q?@{_Qwg$p|{;IJ(tjo>6PJ+AhQ_pW&`U zX-nTu=(e9^87zmL`>#iPUaV-165X<``(7+?v616EyEz0MK6()&3w@+nMP{!-r9CH z8@_r;FBoUum}2&wpsvY!<2Ze7jD9uDTrv`4@LkU}T_2m``vO|PY;)T*I>ZF*z|qOi z`t=Sye~VGDoCWcoQ8e0U;_WgDzEGAMLzC1z)ZEiOnPU8y#aRW-jD_dfTD6R>%B*ye z6Fxmmo>_OAL~F#NZ_QHaCJ#hA(&ib`>Av`5%;BwM;hy-cXu(skz7sH-zevd+{Qtza z+4z1#c|Qgy{oycE;&UYEMaWF7oPyl^3=7;O0&yP1XS{RAv7KkKqgO+wzJy@?kIlR@ zE+2ox&R)yzp2LeZ5l?O;jA$&RYa)zr4$ktdOV{>yr|vMO1~NxigrD66ol41l^lv;_ zK9M!id3N|U?DhgMsR}Tnx^T4DT+tC8)(778wlWeMdYnDOJxM?KR(puRvrw|~N+EZ- z(%#FVYB^wU_d35uTr2JgGaDyI?vnUnPx6>w@{BwlufxJxLDsrLyIRNs^^zPR4I!G( zDee89UbbT#n*l#~Up=cGS?`*!V0Ak@MP`1GGvHrx{o)EOs>8PX zjk@Dzg@b0AKWR@#aajL#PHcSMNE6QIucR@1zmZy!Y`LFou^zLLJejnaZ(Og!nOKdr z^Rcp&ow9&klWBiV!?zmm-08RpGfA3-u3W|A&YQ&E9OLub~%YMQR@ z|F3NjNz+|z?J)tG*!vO-uPK?*PV`t0wGAbk#_}aiWCczlr3TwKz!SAsI+9pzNh_;_ z`M#SCc8LFBhdRDf*9KB(Ejjop3u~ACfAdjX&W~{?ugg9BABBVIWbstIl6M>*%2Mu1 z8n$E2W=6c!56cEM`AX`E9eXY8&yUfKPox#E&C6u%bHS*vw(n2+&YKn1z)ot&+fxhc z=5fBM;+QTs$&;8HLnSw+QhvUX2eHr|x2=I^RTYD!MDRcN-_JjDgv{Q_BlI=j$=59B zEx{QP5GQ$2e)DS%kj8s$_mbUvwC5f^}Wi5X+|%9#;pH{Z9#c$ zu45GjL46*Zmt+yCC$hW&{rm+?jM{9h$}|Ge8nmJcMnu`fW`v-Y@5i8?r znMm)F5#=G8U0K>1EIPP1-X7$o*J9Z&w*|( zO8V0v2S5P_(#qbVC3c4jwuzVHV$SEOS)A02XY!M0=lH&my>V0(Q;&kK^K9^L=#=YR={gTYAiB*)cju(#Gn;TvvWu7O&s>COu`hSy+ z8Mq92_^GY(>zrW+>NvLX2%opTnYYye?MIY}=;`LLyLq_|OR&x0Bg}(*i9SA=k z1`&Q+8ReX@&Yu9Up68r7P~wjul8b4}AJLvO5zm#h*R{0T4Z(Bqr&ujt^Nf8PJVQIK z7w-vbX~$|b+cNPl+Vv1^_jl)?;2}F7RHZGy#7Er=7j!N!-CFPK6R5-r+S*L0L}ow0 z{9p%9v=-uWKI^S)tKOul8rqFGiNgEa{&9kkN){4P2*KDsxJp+ z={}FbU+U@iuS2VP8Rzf7o5qt#5D|LJ$0WwmOPEs?5~-$ZUoa+yDyvAl--8a}6+y=^ zZ_wNL9ZYVF=c`_9jIIl_%NBYYkMTpsdNp3->NuDW;ZWX#H+d}|>n+Z|lh3mvw&Jt6 zo-Hue+TdEYl-s2-Pj4-J%0xSKBoE5aAm_lS}Y=5^NZ*opu8nesX9ZaYrv&$PqCc#%KR6jv)l)zs22c-h&l z$dSHe$OJNDA$dBPZ0JYU)`89yWD`enUmT%%{mBA9Lt6`cPN0b){NtP$i}Nh~6K0xB zKT1McTtgSj>+OiNH0!K|$F74VtfaNAOg7Ppwwa-Rp%GmqO=SHRN%4Vm=elkIyJVs* zAE-B341ScUyH^vnQH?EAG)b}Avp`{T!F+F{0p_D+-D!IZy!IwG!tI{Md?k}dMe(Cg z%URTj{nOCCI;{2bcvwa7t_oe^UR{Bkl@m6U9pZAi-ua&%`1hq=nLGX&vty4@zAO0> zhWwNH_(wSOzi{QVR^gP?2CL%)#`H1x{O)9>xUc2PJie1<@aBbV(Zz83DZEC*bWd?H&}yE{pOV@U&bJ_DDo$rDvsT_xguc;R0s*U|$nkEhew#?tAgV|-7di!GsN zETpe2R;I-t(3{rK!B+C%t)(li;0syB%eR8YGo1t&L2r4J2eCOR@DjbN0bQy&kMC=7 z8KtzN#T>oMx7%rUxBDyPuPk3=T~{=9eoG~DwbVyxOZU-sa`L%m^7GG#?6Mjy_Rgj_ z6@7`J|Ak{;DWBTE))^aQ<@;JDzRZ=|PspEnQO3T1WZgR%?Up%nJND0)(Z{^GAIhJ( zLR8tO(Yw(X;>f;<=E|nGNHoR!@=dG}tG_&IC#LLmN4vUqfM|+|A_HcKPMaYLW1Rc< z$0Ta6=I5+3S5wVp-TeXgE-i;)Rrjub1{hsdkXr?fY?|0Bdiz}6Uuj8))t+lBZZ_TeI8z{Z^4)5)5 zUgn3q;U~T6rrvK)TKjN1`xtuYaDJ>I{8;^Dh8u21m~3`<-|Xo&RfAN*2S@Bto zjvTD`Yj|F6#hkmBrdW}8q86`B)1*I5@ohfIK|T#)o%Ca$43(AUEn~EIvYih3t7zsk zWNk?1W`|Q|GtXv+Jzg!+S}t-UvoHN{D3;?m2<&^%*^h&ctgzS3`%ROdS>pSR+Fg!+ zV-DWP(%Rzqmvn-ka7{CHi6hvQCvb@ln%{TekbaMKk-0Y8A9R!KbeE#EzGk-FY~P{J zj3A@?lg^!G3+O;5zfKeEPH*ds;W?BfA4x(_BA+wQ{74(-Uj~n1_S6b@1dYV$w+UCN-|Dg9cntL6S<+yf)XA5K>9B2VzjkR|xT%fkLoy>zR!(u@LZTWauKPZMbbeCtn@lqYl{Ql;0Ahhu8 zZNv=p(!PVelTqH!Wcd|lYJ=&)o8dg|Hc1;#b-xLob81k+z5?3RngYSi-o@?VS~(Ox z^m(yoTd3Xz!2?QZ=M;1No^W+=XZV@lv&#LK2DgPHJ;NI^Lp>LSGDc-6|Ai0xeVLyt z%D?ci+zSu5u7rCPcF)2=QS7Wc?Y|P=ER@sXTv%4FhMUcPF|GFq{Ng*>#i#I!HG1z7 zOyn8-Gw-mX`pZhx)lAu*XRW34-!OA_Fk^N%3c8vjdqer(q!G90%V_9xbt9=TM)Ni1 z$YcBz-?IW&@lwuX)y;(-EcX2)=-H=`hV9BOpZBv2w;R!0jNFg-SEsNKhww{wfGfNX zP5A%(Qw2m2UMu=At5~HA$(vXL-T0KdLQ;Fe`Z~#C*#YX%N_m;os0;V2&c|8ayjmQe z;4ZjeE*|-qez_Ntu!)X2mwq`T{u7SyuQ@0-`(>B6B#)W#2Ai;1b3)RP{)`!8yV|}*X4C1oA%o=3>_pdnm9E^FzS|5}w-e9)=%f=JH8bP* z5MK7T&CFd$%=VZmFPOof^ZfOorcarv8=3W+id$`E#_rBDKNLISJ+t#hvwJ3w_!uwz z8S?c%_QPrZ@V_B7`&rz3$k6YhJl|{A&$Q_m%0^hvXTE=-oqzOR_ORhkK#ed^Xg{B* zXEWR5XZsJ+iq4Rdfs!IIui=@vnx%dvttN(e9_4TP2}1Rm`>iIUm-9re<=^Idi8Q&Idsh_?s@41f!`Hb>%h$#&6k>mdEJ*(F2ujqY(@{iG*`KwI`pD-4!a$)>m+ z4Xy=7K-*+5`({_%5i3A;eCJML-wa~g^kU<5^tprn)5Q$i&9M%?w_x+sW82lz*D641 zs<7=Ii#LdC7C9V$3*q_Mc0WeRFYK`&u}ij?mDkDw@B!A7wSV-_Y!LcDjNU0&+;Kho z49zt#rf$=RiW-6CjhPBYW6Ag;4n+X>5x+|h{9FEj2nrt>ouO#zh>mz(kN#7SK9SV5 zZKO9oW2DuJ|4S;G`|tPpUafhrr+H8huE-}K+77>EUD6iY=uPaUUM$i+^w7R~b`So8 zPM*G1{5!26z+%YjotDs7%hCnPBm;f!#W&E8&fTBqWguO4uwOjT+Zw{x(#J>{AY!?X z-!xpFy0@J>iNu)1qMplVFq_`76x(D8xssVhZ8cqerC+n$ub*c-TN&&3Pati^(oM#B zg0b#A-V;o~^Pfa&jl-vytd~v3YneqdP3N~*VE+_PHJ;|u*QfS+@N;T=Lan9Ttq7@^ z-<|T4kp&zp%zN>m-d;|<57UIok#xl_aboa{yysX;9QVt1CKJ8Wx!&z^?{TH~xmL@p z(lTqDC!(G8QV>_8AWz9H#!qhL8htpsF_w*ABd2kh+xOdy$-9iFJC)mvk86$X>s*tE z9Jn+2R%>jaF=Zz#2k1&K z^-YAtO!0j_Pw7G$-)h$SG6>KL2+(RM(rReYI@fIsWZz+XZ51E07sh@NW92+8E;pU8 z5G(yY`ducQydul{VfJ}>s9teCfP3J8chCTDg(Fs=@zoUP)RD(|tXX&|55iiUjOEbE zSuE53_!Vt~+H}MgG{($~yaU+ieIb9nXov0D$1T~rOn@t~CVxr}3_ z@l@_}?tSVltP~S#RUF1p(leCeZ@Euiox;2|g&_-fLGlWCuG=6Dh1{o(IFV%VdX^f z6>rrJxio*|0XuAcu47>#jO**oJF$7{G#lV|*zzCjfMa^$VHnJxKL4SfWBluf^?>6v zoYCO41T8%pjm5KNT1qnHEzDcb@&k)^{e`iiKsXZ)jEkOaza+>Be*&Tl-=sz7fjNE zL*2Uz&P7W)WIb=`3FvGET%c;+WKGZgykGj7p3oUe)79wdsdse4C+h5XwZ#m3+3$J* zo24rKw6yaJdi(jcYECVdTZ`p#-pxurJvF~^c1!R8u2x}v=3aNb!LPrTUXonWE57IP z`W1?^KRK_YFYVt&KiEMR$y|?HEETEv4ZYz@Qf@UJVgapUj`R4?$><-+t}VEI>v<}c z(@1$dXtFKIx7SGJc4T;CI#PWW>Eq;H1yZ~m&FN8EMID+;Q*}K@zBM4_D!IOd+Vink zZ}s^Gcf7;#67E%v1g`IyUh@pEc#7s`f_fzA<0RxG&aXs2e%$sMGeaZWMs%DP$j;j8 zt&W9Q##~j-xm8H~7g)nB{HCtz>FZgB(TzsXmPXOj25W^r{L*jI;F@cNX7sj3r1;C& zGYx1?4QWA*wM<*BHdw2Ta89OwF_Qy0T)whFye!@MINQLfUZxe*A)BAX)_HW`VIc^`bLZunZw#Wgg< zrK;w8X1qgrjJ}%6OCmDgP5%U3mTtJa-*49MxzBs&>^al%_RP$o zP5)WG>-Yz(K@Zlz^DCuUs;(Q9wI78#$@U&)#||DecgQej`2=mXHvVKem;wt=FuR7C zWv}xKdXp@qx772T^>x-dI%Oy6CEpUv(`+oyC9Tpbo*%MS8(Nu7%vI8sRi4&-O=)%} zH#@WNq|0y47BpY8NE2bRI&7XU(UTKdXkXW3FQY8vNP6E9sL&XCiT_!JBl%_x)qCB2 zYmLfP7najgWn*LH0S9Q+1GJ2_c}P4!Q&^X#up%$E22KU9%8%w#Z z;%7TZ*M=UXB|f{mk$udJ7=WK0Xf5Hv?Yb$?=Bu z^;%q)l0%rusAVuJY1J(W8RDARb_{I9->kq_{bANEGUNUvTl{X;Ej6>22v^bPtoMGW zb#sI+=M*@NcQ|6k?f`3~T@p__&Fr2k-6!&zVug&cn%+_0G5oY9k~pT*!hVbY_zf&l zhb8L!3!dgn@ji{u{)OT%w37LNd-p#pAy~fyOg8I3wMwU|$LzRv_h%`lEB$@78*AMR zQ|lqt*5f#_M?oi;p`SJ0-THjoT7Fu(=WuT?d4Asd8z`5)xTaoe&|NLVn(AWRwIX5E zv$m_LMMW)fl2<ð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%0D|n zQa!RfQb7MkE%`lZAPJvv(tp$s{@j=rNA76+kRqBDTk~7{2=t7(;k+7_8$zpVU^!v# zv8Jd^1Ph8q`pWvFwp^%texmpZRMlebLgtI-Aiv!;(0LQ%1yOb7tljI^wkvV&1-oF$%1E~QFCCx{cF6C{o1hv%KV zpVkGRhOS$9H`b}_irEn3O3-C&)t;YndgiA%TpD^F$8j*wa0mR`@e%I$f`h?|_Z=RT z&wnjp7rw&Dqxj8dQ$F5AP9DFwiI)d1>AI5-*|X6|9LT>|T&OGJ7-%H>3z}ohEYSOoUb^pSzl?(TK(!b{eX6M9up0N zzMx(3^;~!Q%zf$e#%)d*?V7Pro`Z!je->OU-eh;u^3x>U(a+>Rcq(^m`7@bM_6yeT ztl*aum#ouHQ?t%5-Zu6YR#&tIwBn>gWK(!0l0VXL6v0pd+3hzEH8E63Rutb;a#{#0 zj!MD%6?k8HyE~MElLko%Nyt$Z_6amJnJS6`l>vqoykCnW1;3q@3{CA68Z;Lh8*4R+ z#+f!&<=W8rCSA@`A6$5qupv!+RzEbgHE!0&te|M6*plS>?r&=?y2&XxR_-|^F=?#j z*2f1D!me4#@x{N>)Nr@enaqKgRAzejFe{=)%xyZf1NuWj{WGteK0Do;(qeE-yJZhv%1laHCG@2KDJNmHJKBUi*xv1{ zfp)&+ot})^c*PGsJIOzrxM~1cjH6nV6|bL!kEhp^hkrJ|6PJF) z;n7R6=)$MnNEo{%oR1U5oEF7Giq#ZLDyLDgl5*CjbSnvOAAg_sm89Vdb~TppE9uiK zdG5CoF3t0~gkQ{cKK*uD2g*3kB-qh#fpKu}e^k?$x*_Zsz$u&gJRMv=i(vCcTm`BZfqniQ^;q_~#*YVJ-@SWVnYFye{l zB!%lK^G3pa36Y21?SXMBy?P?yJo-GJPr6fyxmOeY@joX2gZ$cU=lRu-O5!Yh)X!4ah|%ixQu!SziI_6j&ydPdym{dTeJwUr0pS|80- z9VA~Uwn?!=Sc8Y6@x2-8$Pef{al++%X^dGZvOR1V5A@nF@r0>OhOaxTbN#IFPB_l` zU&-%#G@ApLMw4u2^WZAIb9iYyYjdF<^vmV18czetngjm!YPwqkHB>%0sc)o6Qi^YtzHc zT&n!Vs6Y*Nq>3Svkyg9H!D!b1{nmI!M8cfrU>2D@>P8-5hIli&LD7FCH}cmLOy80z zb$qaPVzood%ZA9fapD3UwsfRL#sz5rTRbua(l)kuymiT&oOcEeT`(CN?J)gsJ$Gr4 z#nTj$#POgoUU{&v5@g9pT0jp^4@J-8j`!+0W!1~m!_)iFG?Fji!$>x2V@y*GCuzv^ zKqLXI1u@M#nT5Ob^vQJoq=YQFNIU38d59nUg@?_eR0(5|&No#*VpY-`CP49Uf46r*#M?tCJ3I zw5}ngoLKF`(X722^Q<~>O2(Bj=HK|V78yUnx-MF; zj4?4n%^b586ugKPsWX*?$&9v&RBC0ND+Xq!(OY{`D-Qb{E0>kfO4D`GN~)yhGrAXF z3e+-5n3-gjh$9cP9>dFOr)+C{_YyPSYGA+U%z+Dj&RRcm_km+SQl?h38k;$7jq;j! zyYi7*8gBM6bzu>&EUS~S@?gz7yjR-E9%zNIdye#S?$!=Cq5ahytv!0uC>Ac6z62lQi&eNPsHPpfVp*Zk-d~;|uXvAE! z9raA*jf!f)(bo4Sd_(9AdO^W7W3uYMJZ@bMKCzzpcjl$4YDbp^tqD`TY| zuNfyvXZ+b2?Ha7i?1G-V(+Tgc;cgEfTdUl`+L99NnDi7~HHDF}lD3n&S~xngoj-1?|oQTfCTFU0Ro@;am_H*7zeYO^r7KpYe zdB&P8FnA(W7DXFF*2J0>9Ba9?zj_Fii`vzWPI&E6;adwZRGJHgl$n^8TxNsTHkVk1 znHgrK{Zjh-b4P8V0QI01%ARH?l;4=QzmWi$E!HNIAZg9oTCru_OImxRRlt}Bxl;Jf zz!@Rwd3(JwN1~EDc<2E8Y-R8;fkmi<#L;tPdJ< zT(lWVN=BzZ2Y5B_H|EN?%sW47Q?$JcwmnEy-Rjy#`F%8PkE zlT_Z$<-K{%Oqx^Sw$6tWJDnJO@2SL}$*+H0zOZxQ*3O2TJCk=@uk<)#XUpKL&*gHy zA@11Ix#7Wa`d=pAd5B*p{qe+lJ2t80U- zSx#0wo^s){;CFIrKw_X)Bom&c__~k4GR&iyH|iO=OM1 zyKeTRjQo*NCB_a>ZMxIP&2ck|Y}$Ut+8g)D*5l#KD*GIHpLFEh=y_`hxtKiG3Np2g zc_t6*UK*?K%y#l|l46o!JA&PW>|CCq5b|t>qvgfnJM1uX+FJ6V&&p%reegM?%w40v z#5>_6agMlEl#eyA6pmG|oTW9a{1-0MPQ$w1msIh2_(OWW#-Y%x!?m{^9(A6r$YAg} zCr#sPPx}rE=Si#oyNdr<^RfY6A;<8=a(eSy_c& zO|qDtOCb(qaLS?B4RIUg`r(SgtSvXn)n3wal?itkmp_4JF@z;fr!=1ZwcNNGX)$yi zD6?zi4V6U(4^MPpcVnEk8reC?CA3&+29%l|4sGbdVW~$c>O7~H?QZ1vdKd?blR`&& z*QRzkH1g1&fhR84VC}i})k}KKs4*s`)iY~7kT|pxS-|4uie@o~ zg^_Dib8mKl(a}1+H*k#W&Qd+ub)ci&{I5rx9_|d3rlZih(9zPl+%b>lGmp$H^TsN& zE;~Z6l0Tpp$%^EZVp$K&X0wcZfQ0}(KbjMjioZoi79N=9AkRT}DU>HKdxM_#h1ZtO zyj2%@!9_LW#XXZtDW_$Y{`3pW#a@9-f*hf+`5a2`j{26az6XoE0<2m=v;?)RokVRW zTDQtK#Gu_vor`HXYU)jUl82~A-?g5Ws~nCT1?{XI;S6)QN=tSiU)x&W!`BQJzsT(1 z%3oTEHkq*XS_|>9v z+ijH4QnhrwFkxx*wWdZxcPHW2JRE}&V8nxKO@#xV$_x?TR#7`?lxgiFG0`Gw8mVKR zt!M7#y~?AReb({LAfp&wRwd~gX9ik#%~oq6p3ZD-eAnQytxG&u;CCcj?_0h*81h*C zD*rX3$sM|KSi!{Cs;bh^Wd#A>+Kn=h2S-+(5AM>E7uaj9$lV*P=v^`Ni7|8|kqrM|8AD@tZvziSK zd81QtNETULv({$w!%~MI37=9=wL5a>mr@%f);>;)VnM`uyVlx0M~dYQnen}<-w<&+zr4<# ztFJe>tY6qBfumd}@;jl5#|cXr<@ja^n4W!SM7i}*;B%r}HbPD%67HYXxpTw$ITRmO zIZscjo?N8vU}z7%CQdRE#)E;U2>TuoKvoYHMRM%TKO3rkon-H%Rd=oD zR2Il;ruBRWne7!@F|dVOEP}G0snj zRVkZOUgY)=cV6ZkCbo*k!GqX0siJgvR=7 z#-Xy8b2jC(8`<~mJY9E6SMsp84&zeHW-E;K*SQ?5OL0QhEV;Xmb_KB>m9DnBR40ex zv#z3~Gc+&ms6lin`jS48^-!ffC`O^^M;b@`+sOAq|FP_3yE*nfc_M)! zStO6#5cx~IY(v|TQR4B)BFiJzLJ04O9wY;$O=W9wJ@83Z@QF^`qk$#Csoa#6k+iIp zBI!|j^7NUs$A!;~-$C-y1+iTx-DT%N*5quW@~5>1hnM{9H_)N;Ewu>)8=j<~Bk>$O zXm7z~RgPaJ6(w1knky^+tlLRxYtvdwcJkHgeEBoTUCFSpk!oqZ$wz+GHYM3j>g0>m zciP&wyIAa!Hz|kJiu|w~%=0`gkg}!W9YJ#Jd?2k#GOX1}hNpG&PMZ8T3!&tf_FD3g zPmOhu_oSxlCNE%V!Uy_Vayik*NyBP-J^$)J%0ODc;-55u{Zb`gWC}FrqzYG)LM>MV zjpTt(fqSKM({d1u!&{@b~a{35j) zTbijcO}}>PD@i;xg5?arsHPbVZ7RnL6MXQqc)9M>{ zGc(Mf{Nrb6aL6+IOtLxh+2nOMD^X9Q+sxg}H7ij$<|r=Hodniw_iUvQf)WwpBsclc z1Xh*u=jh;`JBdQ+>VWpMN|Yb?dm2+(?`TR_ZTOuMS9-I$Ig|-XrF0Oe)kdOrP%&s0 zYgxZ}3xkDHw@T7z((U0Y$jEUP&TO+XgJ1dt$3aKflEHJXoORYJY>jP*Bgz+G>V!jFhMy^b8wkHqA{bMhGufXAtt0LpRuCSs3?pK~#dALTU}ozM7w+eVtdUeV=`; zvrf<#h3Bhha{`@TAt46Imt8levEe@;J3B3mrs!nS@lV2?(-mkW5T>Wo7vraD^A_d<+EiX*Z z^z=q&#^@XH^`v-r@cJbrJ=mVqS4NB+Ea>%|uv*C*L-n6_qDe={`n{9~f7_l&<6INZ zMvge6oaWqpInl=GQXaU~i1(fL91gXTM>*GL5oXn%D;FHOebGw{DhV7gSV61fc*5k@ z3`5^ktB%5v&WMGZTqrW}JS}-$f^SCfxS_9a{p!(E{{gX!CV%nu5eBQ)NNTNIJnR42 zU-0E^X~NV77R~SODh8mTzzVm1{90DMO3z8x8k)RXxhTj17M)5 zm4j!}yTbd8F5^)+tb6ZyNO&ge1y6|Oyx!(9$~%vY58feaD%8E+7sAa)vj^19J~b?V zV{Vx}{^j*-beiuClLCC9;^8MAc4}k}*E6?ko!ZHxhH&YOl?P;)=vQTR_0$4V_VjpT z-FN_3JG+CfbmbdU;A=Chi28UdMj#8*v*k)V<{J)|1q+@gAT4+G)}u-)p6*@8!G@Q$ z%(%A3>0Pj-U;3c_G&mJl!L+SeUdp?As!dCg4@T;yOfkhm8+h(m5LW+}_KoyC4-Yis zNLwzmTYEH2E@P~7e!0utxd^V=D@WU%t&p$y}b9%}*~3SM|4|7Zj&j8n+uW2I!DC(*Fa)3%%UH16`0-$Ef&Yc3D3jmizJ zg>vJ!;6SPZN>4OXG9C?HC>2tWMS5Afg*DV-WmIb>bV%iQ>O$&fg}{xG#E`7PNlEGr zPh*6fPVLGgR$2!N2ugyHa&U$uENZ4EC?c`a)e}rTQ9;rvUEiU?tf(j|vO$=Z+q8p# zrG~AYHBxP@r8rczVAr5l=tyg;w0cHsfWAC~C5>Lu+U13P6X4+xN}seG06_h=<7)W<;u&Q z!>mA4V&jST!jCmSNa4J~;o;ND;gJsG^rRABPHvrN zt9_et=@pegn^uinqzcJLgH0BLL!^-diB%0w&sk_RY&3JU=k+XMM@5QJO&a@gUp1%2 zgBwj+JyU4Ld918^pMYCUIt!kh;1Jj(Eb`FK!G%uMJ9{iLb~x0+hmTdYeYAJ-;&yAT zNPEb_Q5|c^Q_Z|^+QDk})L(tb)@xrxONrAR%btW)H^9cOZKy@{gjR0*lSq+hky%yB zH7%8ATru5eZGQ_6YgdW)m7m7CdgXh^SB9>>v|`{`MeI^m7xBIKS(#Q0 zs}mSqkt!dxLv_`$6VP(FcZXBHeOxHdX3$a6R%~mq-Nwq=-KXoJoy2$YrH0 zwPAO#2R2?Dy1F}_J;Tm{Vz8pyPo-Cq-BUihC%yt5QO>}6?P-xaSf#=2JJ|->LJpxy zUw&H?Je^v%TzQ2ky}S^94UFE`IVJDcX?=B<2ae7%D(wpK>#spndzI|{r! z0C=rs>x|Ner_z>m3xuY{je=YL&Il~0hMoskE?6{F`@l;3>4mnu8fZ6V(#*gW?GauAY{>m-9FY~X@;=xf)+pZ%+-u9%?tUZ*} z9&F1<-M(o1Rj#4!lp(i1ue_oyZEb=v`LOv#a^$|G2N5pXwIiW(&*;>;MxQzwoAMe9 zmCdMA+p+Rqy^JRTi$tqDY5iEr-8G&5#izj8j!>>qKI^x9b`C4L)t#KkyOq~&p_lC< z*23~n(%3z$nf497Ggf(d3Q>Gvl)A^M+0EocUw6kry@M}ITzLr)q%NIbIv(_82Xt?| zu*Sfn(4;RWc4FnC%e!;hRU3;Ek*YHI=Ei?06^CP=?Y&fj{P=)q${n}d()tE=v8Z{QaY>nqRHSO4E~J+yH;B0Cv;uy zW6*TUf{*$%uX^=anJ7*AU}00O`0`%(b8zwTxHqF1uT@TnO{ST~OGp}ApuBjmwddiCV}%v25+}zmRhmt>(cJ4H zggfSAQaexlUCV_Noa>nGcPX;l9A|c+$mQIFyu1M8e;s3F`tB(K}N85<6LP*w{d0Gs!3-|=aqEU&HCOh z^RywxqK@1Q9bIFphe1?v+uN0mDjhw zfeUG^6}Nf2k96f#M)S6X?0Ya-?)Lq*jJy8r{tf5CS#Z}YT2MLeZIAY~-NX7~A80RE zx~Y|{@Jc8gE4A?huhvT~;IFloKCt#`bNNbxfU*8$oOo-fXV`Yd6l$C)Nsq!)Y09u(fBExz5YX3Kjet!k%TVE}Sr!7)bdKK5DthSGSH&&Eygu&5>gSYjeqf(yk z2Wni1a&_i_E3FdEnL_R?>qxYwz_PR7xUnw6-5Rb$>mn;ubFC{ISk?lw0#v_BUS9#a zidn0zMApx)4bmy8cQCtlv6NAc6^#rxIU-e5Zl#4VuDq~oENEbM)zUgj0=v+qRZ8~) z>%5qev?k0dZa)&Do|OZ_1Pt|0O-8B-3cRekl~7hBE9Bx$Ysk+Qapx+lr2p2}4}?IFy%svg}#tVgX!>!zl#lfIHw zzkRayYRk5<-@<9i{(@)c(C+?WWHc47e(TQCeM=qX)1G=?&cXrR+qBe#842)`Q+hQs zzN9jSrPRM2UCS7B*Q%wY;RQ-lcWid7>O1A@uRej)-AV|2S}S=w%I!CL*$N9YG=qIi znZ+BX{?%VgnAI?sUyA9IK<<6XqXe~6qCQu;{%DJf>$5Q^cD-%e|5_bvt)~^6zHJSr zvc(po%DRhbL)(t+#icb1tF3K4X#008t@nx<0#a#?mZTJI*_my`w2zEvC3Uuf(YEP~ zk+*Ter8FbN$=}&wwOF6c(see&-0G0liN#${AfY!fQ>Wb%W{%Qz6q_VY4&|ZJmYK`8 zRT;dh{=R&vroRWCGHDz->pYvOR*4BcOlvwM+q%FptTgDA<4^TvE>S%^MaaF+{6l< zT8uqoY7~n`YmXD@_l$R(~kokrqT|iKyKV} zpA!fte*C}}d{Sz0Q)6c?s1y7^ai6*+U+S0Vj1TskX-DVlwY{}b+HLY`zy2BJpcor) z(68FisB2rgPpJvf_u{%2=>0yyK_B)VZbrJ6bQjwZ-B7c2PEpX$`S0v*%FbuwBr8mC zEgkON%rsJ@2CuWO_l7lvlr&s3{^xFeREMs(jqgfVs9lLb?`$=D)u*^DD~*!7E-Trp zp|3Um!>$P6)>ZP}qH17IMI#0`rW+&}#18>-hhf}d{&nR1M^`13JO)|~~ z%F<)4M|-q&FLofQbw_}C-`znx$E~87n z!e}Yt+g_!s)T=A8R)SS?phL8*nyZU{HEF%H_tI1D@YA=#+aJ<(o+Na}eq&n`_^XZj zOWAvSNgrxmkYMDwv)8I_##(9NZ4DZXvPyLYwqBTDiCtTZ_&N;qu5Sact8;Sxe__hB zek6YY(b%WlXw~KC!=TPiL-A*Q@xFEz%jC13fC>I!JZWH@zqNc;R5*4|2;_wOot2J# zdQ!IxHIoml@k$6jT~UKquv1U5T0(xi56t1$RdnD^eA{yHgLA_sZ`yQPD0QEbwD^)j z`CU0PMh3%-q_q;&ed1D^^mJnFE$NxWXQWLn%{cW&En2HPhV^|{{AHKZzv7Jzf6^HX zFqx6QhAHS$p@EiE9UJE8wAPH3;@$Bv<1qO_1am3deHnLVwYQEh<2Vqe9@>$0M@Dk$ z(Ggtg0wh)yFf>=xC=^K`xwoak6K|ZVhp}NEY3a@bbIgpCu45feo)?_z8=hJYjMf6~ z>c#U1T%|2*oVX>-ye~AR=`pz)X3pAampi=L=J4<@eb$zw0lhd*PYsl%jkTM3)7d<0 z!sM{}n)haJ`xREo)|$l_=F6%ff6E2AYgKEaOgPB}#`<0O((~?Z9p$Ns+H0rmH`7k2 z;Pz7EyV9+#V$%}(7k+K0u6)x5(}PMDCrxpMr&`X4PgqBkxWa+8wCVwF!?mokjWFEJ zGV+^G+LRM~w8l~%%#&x@(=NHRzFtvBVgA&hy{cujS8-T+v@^<^mPkv@YM~BRq4iNF zpZ^)HNt?N`)|d4oGoOv&V&8hT)nKN~<;}e~cv5mxq=lxA9Rn?|DOz&JZPOQ4W0#Qz zCoQiniwj6Cx%KX^8u(jqY)RmPw2qP9ZOf(YgPGovLVCXoo<>E->N1z6-BN1_cX!JL*59R1zP77YRnycsVbfOw zIklTKX@T5}g<1$rUnMoFXJ*Ev8wiuGZEZI*bJ8clM1M^kGw^3;8kow4lN8n-DcYAx z(PQf4uH|N(`&%o--!pkqN>WbG2A?HI*9UpjEHIj8%3kZSfoC3qn^sJU-n|Q-+T~up zGj&RefxFi7ZLhZdIz_aWI%&<}wr!u*-_!1En6-^M{?}^?h8nvYGuF+lje`-)jDw7g zHGK4lp4KDiqqe3IuvWLVcsaV4Yg>OtEPg$+KXn=!WGzoeMtfR+^sg|xYY16Om8Th3 zfoi>MDSAeKSjAf(P|ULSjn?c8Sw^_A+dgl7jE2;ItyZmXM`3%Sb8$xfwC2qIKydGv z(V}bpKakd2t~8aBTQ@aP+v2AbfBI==N$S)%spXM=eLO6qt5mTys91IO{y+5|NJd~F z|E)KSxR&1-Sa;SfbFV8%OK(dI1egS~Wq!DKRO*LP$*^hs)FjXTTE38FoGq=XZtWY8 zmwHU-;H>w%7Fof0H4luWEOxkM*g2+PoccEkj-WwO3oCyrt9$%P-tv+f_kdtfd+}m%PQVV|6JLgf+-% zk+e`CSwBKs%`E6T)|O3gr0>_~^x7Ox8J%Bk(bjRsg@UJU!F4d{`0o7fstfn_thB9% nb~eVQ9!pMr+d9H5(3bUH34>q4meC=^AIQ^cYo)iv68L`s)=#UW literal 0 HcmV?d00001 diff --git a/event-queue/etc/Closed-Hi-Hat-1.aif b/event-queue/etc/Closed-Hi-Hat-1.aif new file mode 100644 index 0000000000000000000000000000000000000000..ac248e4f4a57d147454c3b6aea24a8cc802b20e6 GIT binary patch literal 13042 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 0); // test that service is started assertTrue(Audio.isServiceRunning()); From a34e7be9c2377e64c5a2759d053997ef2d340f70 Mon Sep 17 00:00:00 2001 From: Aleksandar Dudukovic Date: Fri, 28 Apr 2017 19:35:19 +0200 Subject: [PATCH 241/492] check commit --- marker/pom.xml | 15 +++++++++++++++ marker/src/main/java/App.java | 6 ++++++ pom.xml | 1 + 3 files changed, 22 insertions(+) create mode 100644 marker/pom.xml create mode 100644 marker/src/main/java/App.java diff --git a/marker/pom.xml b/marker/pom.xml new file mode 100644 index 000000000..99dca27a3 --- /dev/null +++ b/marker/pom.xml @@ -0,0 +1,15 @@ + + + + java-design-patterns + com.iluwatar + 1.16.0-SNAPSHOT + + 4.0.0 + + marker + + + \ No newline at end of file diff --git a/marker/src/main/java/App.java b/marker/src/main/java/App.java new file mode 100644 index 000000000..233db22c9 --- /dev/null +++ b/marker/src/main/java/App.java @@ -0,0 +1,6 @@ +/** + * Created by Alexis on 28-Apr-17. + */ +public class App { + +} diff --git a/pom.xml b/pom.xml index a45f0e1f3..7ca284557 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,7 @@ converter guarded-suspension balking + marker From 8530d01e10b092d47a0b61559b2ca9eb10767011 Mon Sep 17 00:00:00 2001 From: Aleksandar Dudukovic Date: Sat, 29 Apr 2017 16:35:57 +0200 Subject: [PATCH 242/492] code implemented --- marker/src/main/java/App.java | 7 +++++++ marker/src/main/java/Guard.java | 10 ++++++++++ marker/src/main/java/Permission.java | 7 +++++++ 3 files changed, 24 insertions(+) create mode 100644 marker/src/main/java/Guard.java create mode 100644 marker/src/main/java/Permission.java diff --git a/marker/src/main/java/App.java b/marker/src/main/java/App.java index 233db22c9..ca8c036f7 100644 --- a/marker/src/main/java/App.java +++ b/marker/src/main/java/App.java @@ -2,5 +2,12 @@ * Created by Alexis on 28-Apr-17. */ public class App { + public static void main(String[] args) { + Guard guard = new Guard(); + if (guard instanceof Permission) { + guard.enter(); + } + } } + diff --git a/marker/src/main/java/Guard.java b/marker/src/main/java/Guard.java new file mode 100644 index 000000000..93db6b4d7 --- /dev/null +++ b/marker/src/main/java/Guard.java @@ -0,0 +1,10 @@ +/** + * Created by Alexis on 29-Apr-17. + */ +public class Guard implements Permission { + + protected static void enter() { + System.out.println("You can enter"); + } + +} diff --git a/marker/src/main/java/Permission.java b/marker/src/main/java/Permission.java new file mode 100644 index 000000000..a422e955c --- /dev/null +++ b/marker/src/main/java/Permission.java @@ -0,0 +1,7 @@ +/** + * Created by Alexis on 29-Apr-17. + * Interface without any methods + * Marker interface is based on that assumption + */ +public interface Permission { +} From 3ed6cc19d2f8e7365a1a13e8732c7bced72b9387 Mon Sep 17 00:00:00 2001 From: ytian90 Date: Sun, 30 Apr 2017 00:19:50 -0700 Subject: [PATCH 243/492] fix Block 3 case --- .../src/main/java/com/iluwatar/featuretoggle/App.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java index 29676e0c9..97c184fec 100644 --- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java +++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java @@ -25,6 +25,7 @@ package com.iluwatar.featuretoggle; import com.iluwatar.featuretoggle.pattern.Service; import com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion; +import com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion; import com.iluwatar.featuretoggle.user.User; import com.iluwatar.featuretoggle.user.UserGroup; import org.slf4j.Logger; @@ -85,6 +86,8 @@ public class App { LOGGER.info(welcomeMessageturnedOff); // -------------------------------------------- + + Service service2 = new TieredFeatureToggleVersion(); final User paidUser = new User("Jamie Coder"); final User freeUser = new User("Alan Defect"); @@ -92,8 +95,8 @@ public class App { UserGroup.addUserToPaidGroup(paidUser); UserGroup.addUserToFreeGroup(freeUser); - final String welcomeMessagePaidUser = service.getWelcomeMessage(paidUser); - final String welcomeMessageFreeUser = service.getWelcomeMessage(freeUser); + final String welcomeMessagePaidUser = service2.getWelcomeMessage(paidUser); + final String welcomeMessageFreeUser = service2.getWelcomeMessage(freeUser); LOGGER.info(welcomeMessageFreeUser); LOGGER.info(welcomeMessagePaidUser); } From 03aa99c55f58b487b2d1667e0c0824a59ed12195 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Tue, 2 May 2017 20:18:05 +0300 Subject: [PATCH 244/492] Update AdvancedSorceressTest.java --- .../dependency/injection/AdvancedSorceressTest.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java index eadb0b931..6b7588db8 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java @@ -26,15 +26,8 @@ import com.iluwatar.dependency.injection.utils.InMemoryAppender; import org.junit.After; import org.junit.Before; import org.junit.Test; - import static org.junit.Assert.assertEquals; -/** - * Date: 28/04/17 - 7:40 AM - * - * @author Stanislav Kapinus - */ - public class AdvancedSorceressTest { private InMemoryAppender appender; From 2b229d8ea12d4fff57e5896fef55b855d4614797 Mon Sep 17 00:00:00 2001 From: kapinuss Date: Tue, 2 May 2017 20:38:08 +0300 Subject: [PATCH 245/492] Update AdvancedSorceressTest.java --- .../iluwatar/dependency/injection/AdvancedSorceressTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java index 6b7588db8..a8badef78 100644 --- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java +++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedSorceressTest.java @@ -46,6 +46,7 @@ public class AdvancedSorceressTest { * Test if the {@link AdvancedSorceress} smokes whatever instance of {@link Tobacco} is passed to her * through the setter's parameter */ + @Test public void testSmokeEveryThing() throws Exception { @@ -64,7 +65,5 @@ public class AdvancedSorceressTest { // ... and nothing else is happening. assertEquals(tobaccos.length, appender.getLogSize()); - } - } From 678524704c5a710d42f75d5d0c96fd74b31acea6 Mon Sep 17 00:00:00 2001 From: SrdjanPaunovic Date: Wed, 3 May 2017 13:21:13 +0200 Subject: [PATCH 246/492] Test done --- extension-objects/pom.xml | 8 ++++- extension-objects/src/main/java/App.java | 3 +- .../CommanderExtension.java | 2 ++ .../java/concreteextensions/Commander.java | 5 +++ .../java/concreteextensions/Sergeant.java | 2 +- .../main/java/concreteextensions/Soldier.java | 2 +- extension-objects/src/test/java/AppTest.java | 16 +++++++++ .../concreteextensions/CommanderTest.java | 19 +++++++++++ .../java/concreteextensions/SergeantTest.java | 19 +++++++++++ .../java/concreteextensions/SoldierTest.java | 19 +++++++++++ .../test/java/units/CommanderUnitTest.java | 22 +++++++++++++ .../src/test/java/units/SergeantUnitTest.java | 22 +++++++++++++ .../src/test/java/units/SoldierUnitTest.java | 24 ++++++++++++++ .../src/test/java/units/UnitTest.java | 33 +++++++++++++++++++ 14 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 extension-objects/src/test/java/AppTest.java create mode 100644 extension-objects/src/test/java/concreteextensions/CommanderTest.java create mode 100644 extension-objects/src/test/java/concreteextensions/SergeantTest.java create mode 100644 extension-objects/src/test/java/concreteextensions/SoldierTest.java create mode 100644 extension-objects/src/test/java/units/CommanderUnitTest.java create mode 100644 extension-objects/src/test/java/units/SergeantUnitTest.java create mode 100644 extension-objects/src/test/java/units/SoldierUnitTest.java create mode 100644 extension-objects/src/test/java/units/UnitTest.java diff --git a/extension-objects/pom.xml b/extension-objects/pom.xml index afdf010a2..77f6ccfa2 100644 --- a/extension-objects/pom.xml +++ b/extension-objects/pom.xml @@ -10,6 +10,12 @@ 4.0.0 extension-objects + + + junit + junit + + - \ No newline at end of file + diff --git a/extension-objects/src/main/java/App.java b/extension-objects/src/main/java/App.java index 9aa934580..af76682b8 100644 --- a/extension-objects/src/main/java/App.java +++ b/extension-objects/src/main/java/App.java @@ -38,6 +38,7 @@ public class App { SergeantExtension sergeantExtension = (SergeantExtension) unit.getUnitExtension("SergeantExtension"); CommanderExtension commanderExtension = (CommanderExtension) unit.getUnitExtension("CommanderExtension"); + //if unit have extension call the method if (soldierExtension != null) { soldierExtension.soldierReady(); } else { @@ -51,7 +52,7 @@ public class App { } if (commanderExtension != null) { - // commanderExtension.sergeantReady(); + commanderExtension.commanderReady(); } else { System.out.println(unit.getName() + " without CommanderExtension"); } diff --git a/extension-objects/src/main/java/abstractextensions/CommanderExtension.java b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java index aa716a3ae..3088c9f86 100644 --- a/extension-objects/src/main/java/abstractextensions/CommanderExtension.java +++ b/extension-objects/src/main/java/abstractextensions/CommanderExtension.java @@ -4,4 +4,6 @@ package abstractextensions; * Created by Srdjan on 27-Apr-17. */ public interface CommanderExtension extends UnitExtension { + + void commanderReady(); } diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java index 3de4d124a..3ce183afb 100644 --- a/extension-objects/src/main/java/concreteextensions/Commander.java +++ b/extension-objects/src/main/java/concreteextensions/Commander.java @@ -13,4 +13,9 @@ public class Commander implements CommanderExtension { public Commander(CommanderUnit commanderUnit) { this.unit = commanderUnit; } + + @Override + public void commanderReady() { + System.out.println("[Commander] " + unit.getName() + " is ready!"); + } } diff --git a/extension-objects/src/main/java/concreteextensions/Sergeant.java b/extension-objects/src/main/java/concreteextensions/Sergeant.java index b2d4485c3..499ea4f63 100644 --- a/extension-objects/src/main/java/concreteextensions/Sergeant.java +++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java @@ -16,6 +16,6 @@ public class Sergeant implements SergeantExtension { @Override public void sergeantReady() { - System.out.println("[Sergeant] " + unit.getName() + " do command! "); + System.out.println("[Sergeant] " + unit.getName() + " is ready! "); } } diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java index e2d11e244..844abd57a 100644 --- a/extension-objects/src/main/java/concreteextensions/Soldier.java +++ b/extension-objects/src/main/java/concreteextensions/Soldier.java @@ -16,6 +16,6 @@ public class Soldier implements SoldierExtension { @Override public void soldierReady() { - System.out.println("[Solider] " + unit.getName() + " do command"); + System.out.println("[Solider] " + unit.getName() + " is ready!"); } } diff --git a/extension-objects/src/test/java/AppTest.java b/extension-objects/src/test/java/AppTest.java new file mode 100644 index 000000000..88ba70da9 --- /dev/null +++ b/extension-objects/src/test/java/AppTest.java @@ -0,0 +1,16 @@ +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class AppTest { + @Test + public void main() throws Exception { + + String[] args = {}; + App.main(args); + } + +} \ No newline at end of file diff --git a/extension-objects/src/test/java/concreteextensions/CommanderTest.java b/extension-objects/src/test/java/concreteextensions/CommanderTest.java new file mode 100644 index 000000000..a5ac7b506 --- /dev/null +++ b/extension-objects/src/test/java/concreteextensions/CommanderTest.java @@ -0,0 +1,19 @@ +package concreteextensions; + +import org.junit.Test; +import units.CommanderUnit; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class CommanderTest { + @Test + public void commanderReady() throws Exception { + final Commander commander = new Commander(new CommanderUnit("CommanderUnitTest")); + + commander.commanderReady(); + } + +} \ No newline at end of file diff --git a/extension-objects/src/test/java/concreteextensions/SergeantTest.java b/extension-objects/src/test/java/concreteextensions/SergeantTest.java new file mode 100644 index 000000000..163d5c1fc --- /dev/null +++ b/extension-objects/src/test/java/concreteextensions/SergeantTest.java @@ -0,0 +1,19 @@ +package concreteextensions; + +import org.junit.Test; +import units.SergeantUnit; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class SergeantTest { + @Test + public void sergeantReady() throws Exception { + final Sergeant sergeant = new Sergeant(new SergeantUnit("SergeantUnitTest")); + + sergeant.sergeantReady(); + } + +} \ No newline at end of file diff --git a/extension-objects/src/test/java/concreteextensions/SoldierTest.java b/extension-objects/src/test/java/concreteextensions/SoldierTest.java new file mode 100644 index 000000000..dde222d61 --- /dev/null +++ b/extension-objects/src/test/java/concreteextensions/SoldierTest.java @@ -0,0 +1,19 @@ +package concreteextensions; + +import org.junit.Test; +import units.SoldierUnit; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class SoldierTest { + @Test + public void soldierReady() throws Exception { + final Soldier soldier = new Soldier(new SoldierUnit("SoldierUnitTest")); + + soldier.soldierReady(); + } + +} \ No newline at end of file diff --git a/extension-objects/src/test/java/units/CommanderUnitTest.java b/extension-objects/src/test/java/units/CommanderUnitTest.java new file mode 100644 index 000000000..1ec498d91 --- /dev/null +++ b/extension-objects/src/test/java/units/CommanderUnitTest.java @@ -0,0 +1,22 @@ +package units; + +import abstractextensions.CommanderExtension; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class CommanderUnitTest { + @Test + public void getUnitExtension() throws Exception { + + final Unit unit = new CommanderUnit("CommanderUnitName"); + + assertNull(unit.getUnitExtension("SoldierExtension")); + assertNull(unit.getUnitExtension("SergeantExtension")); + assertNotNull((CommanderExtension)unit.getUnitExtension("CommanderExtension")); + } + +} \ No newline at end of file diff --git a/extension-objects/src/test/java/units/SergeantUnitTest.java b/extension-objects/src/test/java/units/SergeantUnitTest.java new file mode 100644 index 000000000..8fe62298c --- /dev/null +++ b/extension-objects/src/test/java/units/SergeantUnitTest.java @@ -0,0 +1,22 @@ +package units; + +import abstractextensions.SergeantExtension; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class SergeantUnitTest { + @Test + public void getUnitExtension() throws Exception { + + final Unit unit = new SergeantUnit("SergeantUnitName"); + + assertNull(unit.getUnitExtension("SoldierExtension")); + assertNotNull((SergeantExtension)unit.getUnitExtension("SergeantExtension")); + assertNull(unit.getUnitExtension("CommanderExtension")); + } + +} \ No newline at end of file diff --git a/extension-objects/src/test/java/units/SoldierUnitTest.java b/extension-objects/src/test/java/units/SoldierUnitTest.java new file mode 100644 index 000000000..8d1fe5667 --- /dev/null +++ b/extension-objects/src/test/java/units/SoldierUnitTest.java @@ -0,0 +1,24 @@ +package units; + +import abstractextensions.SoldierExtension; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class SoldierUnitTest { + @Test + public void getUnitExtension() throws Exception { + + final Unit unit = new SoldierUnit("SoldierUnitName"); + + assertNotNull((SoldierExtension)unit.getUnitExtension("SoldierExtension")); + assertNull(unit.getUnitExtension("SergeantExtension")); + assertNull(unit.getUnitExtension("CommanderExtension")); + + + } + +} \ No newline at end of file diff --git a/extension-objects/src/test/java/units/UnitTest.java b/extension-objects/src/test/java/units/UnitTest.java new file mode 100644 index 000000000..08fd10d8e --- /dev/null +++ b/extension-objects/src/test/java/units/UnitTest.java @@ -0,0 +1,33 @@ +package units; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Created by Srdjan on 03-May-17. + */ +public class UnitTest { + + private Unit unit; + + @Test + public void testConstGetSet() throws Exception { + final String name = "testName"; + final Unit unit = new Unit(name); + assertEquals(name,unit.getName()); + + final String newName = "newName"; + unit.setName(newName); + assertEquals(newName,unit.getName()); + + + assertNull(unit.getUnitExtension("")); + assertNull(unit.getUnitExtension("SoldierExtension")); + assertNull(unit.getUnitExtension("SergeantExtension")); + assertNull(unit.getUnitExtension("CommanderExtension")); + } + +} \ No newline at end of file From 20062faae69c8a3b9b2b7d15080e13cc5bda5667 Mon Sep 17 00:00:00 2001 From: Aleksandar Dudukovic Date: Wed, 3 May 2017 17:50:35 +0200 Subject: [PATCH 247/492] All without Readme and pumlid --- marker/etc/MarkerDiagram.png | Bin 0 -> 6461 bytes marker/etc/MarkerDiagram.ucls | 41 ++++++++++++++++++++++++++++ marker/pom.xml | 15 ++++++++++ marker/src/main/java/App.java | 31 +++++++++++++++++++++ marker/src/main/java/Thief.java | 12 ++++++++ marker/src/test/java/AppTest.java | 17 ++++++++++++ marker/src/test/java/GuardTest.java | 16 +++++++++++ marker/src/test/java/ThiefTest.java | 15 ++++++++++ 8 files changed, 147 insertions(+) create mode 100644 marker/etc/MarkerDiagram.png create mode 100644 marker/etc/MarkerDiagram.ucls create mode 100644 marker/src/main/java/Thief.java create mode 100644 marker/src/test/java/AppTest.java create mode 100644 marker/src/test/java/GuardTest.java create mode 100644 marker/src/test/java/ThiefTest.java diff --git a/marker/etc/MarkerDiagram.png b/marker/etc/MarkerDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed4f9c567809787d9317733a2e4fe40cbe3284c GIT binary patch literal 6461 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 WzLyy+Lj79=qN54ic(48-^uGXLahsh0 literal 0 HcmV?d00001 diff --git a/marker/etc/MarkerDiagram.ucls b/marker/etc/MarkerDiagram.ucls new file mode 100644 index 000000000..0f8376e40 --- /dev/null +++ b/marker/etc/MarkerDiagram.ucls @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/marker/pom.xml b/marker/pom.xml index 99dca27a3..74969d2eb 100644 --- a/marker/pom.xml +++ b/marker/pom.xml @@ -10,6 +10,21 @@ 4.0.0 marker + + + org.junit.jupiter + junit-jupiter-api + RELEASE + + + junit + junit + + + junit + junit + + \ No newline at end of file diff --git a/marker/src/main/java/App.java b/marker/src/main/java/App.java index ca8c036f7..10ec017df 100644 --- a/marker/src/main/java/App.java +++ b/marker/src/main/java/App.java @@ -1,12 +1,43 @@ /** * Created by Alexis on 28-Apr-17. + * With Marker interface idea is to make empty interface and extend it. + * Basically it is just to identify the special objects from normal objects. + * Like in case of serialization , objects that need to be serialized must implement serializable interface + * (it is empty interface) and down the line writeObject() method must be checking + * if it is a instance of serializable or not. + *