messages = new ArrayList<>();
public MessageCollectorMember(String name) {
this.name = name;
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/App.java b/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
index 9bfc32952..09c027401 100644
--- a/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
@@ -1,83 +1,83 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.datamapper;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 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 Logger log = LoggerFactory.getLogger(App.class);
- private static final String STUDENT_STRING = "App.main(), student : ";
-
-
- /**
- * Program entry point.
- *
- * @param args command line args.
- */
- public static void main(final String... args) {
-
- /* Create new data mapper for type 'first' */
- final var mapper = new StudentDataMapperImpl();
-
- /* Create new student */
- var student = new Student(1, "Adam", 'A');
-
- /* Add student in respectibe store */
- mapper.insert(student);
-
- log.debug(STUDENT_STRING + student + ", is inserted");
-
- /* Find this student */
- final var studentToBeFound = mapper.find(student.getStudentId());
-
- log.debug(STUDENT_STRING + studentToBeFound + ", is searched");
-
- /* Update existing student object */
- student = new Student(student.getStudentId(), "AdamUpdated", 'A');
-
- /* Update student in respectibe db */
- mapper.update(student);
-
- log.debug(STUDENT_STRING + student + ", is updated");
- log.debug(STUDENT_STRING + student + ", is going to be deleted");
-
- /* Delete student in db */
- mapper.delete(student);
- }
-
- private App() {
- }
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.datamapper;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 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 Logger log = LoggerFactory.getLogger(App.class);
+ private static final String STUDENT_STRING = "App.main(), student : ";
+
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args.
+ */
+ public static void main(final String... args) {
+
+ /* Create new data mapper for type 'first' */
+ final var mapper = new StudentDataMapperImpl();
+
+ /* Create new student */
+ var student = new Student(1, "Adam", 'A');
+
+ /* Add student in respectibe store */
+ mapper.insert(student);
+
+ log.debug(STUDENT_STRING + student + ", is inserted");
+
+ /* Find this student */
+ final var studentToBeFound = mapper.find(student.getStudentId());
+
+ log.debug(STUDENT_STRING + studentToBeFound + ", is searched");
+
+ /* Update existing student object */
+ student = new Student(student.getStudentId(), "AdamUpdated", 'A');
+
+ /* Update student in respectibe db */
+ mapper.update(student);
+
+ log.debug(STUDENT_STRING + student + ", is updated");
+ log.debug(STUDENT_STRING + student + ", is going to be deleted");
+
+ /* Delete student in db */
+ mapper.delete(student);
+ }
+
+ private App() {
+ }
+}
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 85ad4aa8d..7abe04e3f 100644
--- a/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java
@@ -33,7 +33,7 @@ import java.util.Optional;
public final class StudentDataMapperImpl implements StudentDataMapper {
/* Note: Normally this would be in the form of an actual database */
- private List students = new ArrayList<>();
+ private final List students = new ArrayList<>();
@Override
public Optional find(int studentId) {
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/module-info.java b/data-mapper/src/main/java/com/iluwatar/datamapper/module-info.java
deleted file mode 100644
index 7abd78826..000000000
--- a/data-mapper/src/main/java/com/iluwatar/datamapper/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.datamapper {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/data-transfer-object/README.md b/data-transfer-object/README.md
index e9286ce03..fd0ff1137 100644
--- a/data-transfer-object/README.md
+++ b/data-transfer-object/README.md
@@ -64,7 +64,7 @@ Customer resource class acts as the server for customer information.
```java
public class CustomerResource {
- private List customers;
+ private final List customers;
public CustomerResource(List customers) {
this.customers = customers;
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
index 7e4b8340d..d0a153f6f 100644
--- a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java
+++ b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/CustomerResource.java
@@ -30,7 +30,7 @@ import java.util.List;
* has all customer details.
*/
public class CustomerResource {
- private List customers;
+ private final List customers;
/**
* Initialise resource with existing customers.
diff --git a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/module-info.java b/data-transfer-object/src/main/java/com/iluwatar/datatransfer/module-info.java
deleted file mode 100644
index 25685d4d0..000000000
--- a/data-transfer-object/src/main/java/com/iluwatar/datatransfer/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.datatransfer {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/decorator/README.md b/decorator/README.md
index a9dd5d745..26dbd1803 100644
--- a/decorator/README.md
+++ b/decorator/README.md
@@ -70,7 +70,7 @@ public class ClubbedTroll implements Troll {
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
- private Troll decorated;
+ private final Troll decorated;
public ClubbedTroll(Troll decorated) {
this.decorated = decorated;
diff --git a/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java
index 70fd15489..74a1434e1 100644
--- a/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java
+++ b/decorator/src/main/java/com/iluwatar/decorator/ClubbedTroll.java
@@ -33,7 +33,7 @@ public class ClubbedTroll implements Troll {
private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class);
- private Troll decorated;
+ private final Troll decorated;
public ClubbedTroll(Troll decorated) {
this.decorated = decorated;
diff --git a/decorator/src/main/java/com/iluwatar/decorator/module-info.java b/decorator/src/main/java/com/iluwatar/decorator/module-info.java
deleted file mode 100644
index 50d17f022..000000000
--- a/decorator/src/main/java/com/iluwatar/decorator/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.decorator {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java
index c9f62407c..a398135e6 100644
--- a/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java
+++ b/decorator/src/test/java/com/iluwatar/decorator/SimpleTrollTest.java
@@ -68,7 +68,7 @@ public class SimpleTrollTest {
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/delegation/src/main/java/com/iluwatar/delegation/module-info.java b/delegation/src/main/java/com/iluwatar/delegation/module-info.java
deleted file mode 100644
index 156477cde..000000000
--- a/delegation/src/main/java/com/iluwatar/delegation/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.delegation {
- requires org.slf4j;
-}
\ No newline at end of file
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 2da1e0571..8aefc4b56 100644
--- a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
+++ b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
@@ -86,7 +86,7 @@ public class DelegateTest {
*/
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/dependency-injection/README.md b/dependency-injection/README.md
index 90edd4061..b47c1d2f9 100644
--- a/dependency-injection/README.md
+++ b/dependency-injection/README.md
@@ -9,12 +9,78 @@ tags:
---
## Intent
-Dependency Injection is a software design pattern in which one or
-more dependencies (or services) are injected, or passed by reference, into a
-dependent object (or client) and are made part of the client's state. The
-pattern separates the creation of a client's dependencies from its own
-behavior, which allows program designs to be loosely coupled and to follow the
-inversion of control and single responsibility principles.
+Dependency Injection is a software design pattern in which one or more dependencies (or services) are injected, or
+passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates
+the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and
+to follow the inversion of control and single responsibility principles.
+
+## Explanation
+Real world example
+
+> The old wizard likes to fill his pipe and smoke tobacco once in a while. However, he doesn't want to depend on a single tobacco brand only but likes to be able to enjoy them all interchangeably.
+
+In plain words
+
+> Dependency Injection separates creation of client's dependencies from its own behavior.
+
+Wikipedia says
+
+> In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies.
+
+**Programmatic Example**
+
+Let's first introduce the tobacco brands.
+
+```java
+public abstract class Tobacco {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class);
+
+ public void smoke(Wizard wizard) {
+ LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(),
+ this.getClass().getSimpleName());
+ }
+}
+
+public class SecondBreakfastTobacco extends Tobacco {
+}
+
+public class RivendellTobacco extends Tobacco {
+}
+
+public class OldTobyTobacco extends Tobacco {
+}
+```
+
+Next here's the wizard class hierarchy.
+
+```java
+public interface Wizard {
+
+ void smoke();
+}
+
+public class AdvancedWizard implements Wizard {
+
+ private final Tobacco tobacco;
+
+ public AdvancedWizard(Tobacco tobacco) {
+ this.tobacco = tobacco;
+ }
+
+ @Override
+ public void smoke() {
+ tobacco.smoke(this);
+ }
+}
+```
+
+And lastly we can show how easy it is to give the old wizard any brand of tobacco.
+
+```java
+ var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
+ advancedWizard.smoke();
+```
## Class diagram

@@ -22,5 +88,12 @@ inversion of control and single responsibility principles.
## Applicability
Use the Dependency Injection pattern when
-* when you need to remove knowledge of concrete implementation from object
-* to enable unit testing of classes in isolation using mock objects or stubs
+* When you need to remove knowledge of concrete implementation from object
+* To enable unit testing of classes in isolation using mock objects or stubs
+
+## Credits
+
+* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd)
+* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871)
+* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1)
+* [Google Guice Tutorial: Open source Java based dependency injection framework](https://www.amazon.com/gp/product/B083P7DZ8M/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B083P7DZ8M&linkId=04f0f902c877921e45215b624a124bfe)
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
index e0c952186..f0ff2da94 100644
--- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
@@ -29,7 +29,7 @@ package com.iluwatar.dependency.injection;
*/
public class AdvancedWizard implements Wizard {
- private Tobacco tobacco;
+ private final Tobacco tobacco;
public AdvancedWizard(Tobacco tobacco) {
this.tobacco = tobacco;
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
index 319a635eb..d769ffd46 100644
--- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
@@ -31,7 +31,7 @@ import javax.inject.Inject;
*/
public class GuiceWizard implements Wizard {
- private Tobacco tobacco;
+ private final Tobacco tobacco;
@Inject
public GuiceWizard(Tobacco tobacco) {
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
index 40bca0ffb..0136ff69f 100644
--- a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
@@ -29,7 +29,7 @@ package com.iluwatar.dependency.injection;
*/
public class SimpleWizard implements Wizard {
- private OldTobyTobacco tobacco = new OldTobyTobacco();
+ private final OldTobyTobacco tobacco = new OldTobyTobacco();
public void smoke() {
tobacco.smoke(this);
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 9d0ad1b3b..d91099af9 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
@@ -37,7 +37,7 @@ import java.util.List;
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java b/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java
index db60924c1..1d4fbfa75 100644
--- a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java
+++ b/dirty-flag/src/main/java/com/iluwatar/dirtyflag/World.java
@@ -34,7 +34,7 @@ import java.util.List;
public class World {
private List countries;
- private DataFetcher df;
+ private final DataFetcher df;
public World() {
this.countries = new ArrayList();
diff --git a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/module-info.java b/dirty-flag/src/main/java/com/iluwatar/dirtyflag/module-info.java
deleted file mode 100644
index bf47d2cd7..000000000
--- a/dirty-flag/src/main/java/com/iluwatar/dirtyflag/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.dirtyflag {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java b/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java
index 5f683cf1e..4b974a2e8 100644
--- a/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java
+++ b/double-buffer/src/main/java/com/iluwatar/doublebuffer/FrameBuffer.java
@@ -33,7 +33,7 @@ public class FrameBuffer implements Buffer {
public static final int WIDTH = 10;
public static final int HEIGHT = 8;
- private Pixel[] pixels = new Pixel[WIDTH * HEIGHT];
+ private final Pixel[] pixels = new Pixel[WIDTH * HEIGHT];
public FrameBuffer() {
clearAll();
diff --git a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java
index 501797743..54f130b1d 100644
--- a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java
+++ b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Pixel.java
@@ -31,7 +31,7 @@ public enum Pixel {
WHITE(0),
BLACK(1);
- private int color;
+ private final int color;
Pixel(int color) {
this.color = color;
diff --git a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java
index 2c1503918..8ee72ded4 100644
--- a/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java
+++ b/double-buffer/src/main/java/com/iluwatar/doublebuffer/Scene.java
@@ -35,7 +35,7 @@ public class Scene {
private static final Logger LOGGER = LoggerFactory.getLogger(Scene.class);
- private Buffer[] frameBuffers;
+ private final Buffer[] frameBuffers;
private int current;
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/module-info.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/module-info.java
deleted file mode 100644
index 4f4216ea7..000000000
--- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.doublecheckedlocking {
- requires org.slf4j;
-}
\ No newline at end of file
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 e8ea7c6f8..fe0cbf5e9 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
@@ -109,7 +109,7 @@ public class InventoryTest {
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
index bd832287c..ea18ca3dc 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
@@ -28,10 +28,10 @@ package com.iluwatar.doubledispatch;
*/
public class Rectangle {
- private int left;
- private int top;
- private int right;
- private int bottom;
+ private final int left;
+ private final int top;
+ private final int right;
+ private final int bottom;
/**
* Constructor.
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/module-info.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/module-info.java
deleted file mode 100644
index b1bc2e824..000000000
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.doubledispatch {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/eip-message-channel/src/main/java/com/iluwatar/eip/message/channel/module-info.java b/eip-message-channel/src/main/java/com/iluwatar/eip/message/channel/module-info.java
deleted file mode 100644
index b904ee1c8..000000000
--- a/eip-message-channel/src/main/java/com/iluwatar/eip/message/channel/module-info.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.eipmessagechannel {
- requires org.slf4j;
- requires camel.core;
-}
\ No newline at end of file
diff --git a/eip-publish-subscribe/src/main/java/com/iluwatar/eip/publish/subscribe/module-info.java b/eip-publish-subscribe/src/main/java/com/iluwatar/eip/publish/subscribe/module-info.java
deleted file mode 100644
index 50eab8360..000000000
--- a/eip-publish-subscribe/src/main/java/com/iluwatar/eip/publish/subscribe/module-info.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.eippublishsubscribe {
- requires org.slf4j;
- requires camel.core;
-}
\ No newline at end of file
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
index 7a125c042..91bb020ee 100644
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
@@ -31,7 +31,7 @@ public enum Event {
STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED(
"Traitor detected");
- private String description;
+ private final String description;
Event(String description) {
this.description = description;
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
index 9985cee60..7d3f32a68 100644
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
@@ -31,7 +31,7 @@ import java.util.List;
*/
public abstract class EventEmitter {
- private List observers;
+ private final List observers;
public EventEmitter() {
observers = new LinkedList<>();
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
index 9ec61339c..1e0ce9491 100644
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
@@ -36,7 +36,7 @@ public enum Weekday {
SATURDAY("Saturday"),
SUNDAY("Sunday");
- private String description;
+ private final String description;
Weekday(String description) {
this.description = description;
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/module-info.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/module-info.java
deleted file mode 100644
index 93ebd3173..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.eventaggregator {
- requires org.slf4j;
-}
\ No newline at end of file
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 a8bb6cbaa..f8aa5cb37 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
@@ -74,7 +74,7 @@ public class KingJoffreyTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class> clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
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 6925a2ffd..68c4c9781 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
@@ -33,9 +33,9 @@ public class Event implements IEvent, Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(Event.class);
- private int eventId;
- private int eventTime;
- private boolean isSynchronous;
+ private final int eventId;
+ private final int eventTime;
+ private final boolean isSynchronous;
private Thread thread;
private boolean isComplete = false;
private ThreadCompleteListener eventListener;
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 14d28860b..55671fd82 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
@@ -43,8 +43,8 @@ public class EventManager implements ThreadCompleteListener {
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;
+ private final Random rand;
+ private final Map eventPool;
private static final String DOES_NOT_EXIST = " does not exist.";
diff --git a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/module-info.java b/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/module-info.java
deleted file mode 100644
index aa9b6c29d..000000000
--- a/event-asynchronous/src/main/java/com/iluwatar/event/asynchronous/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.eventasynchronous {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
index c18426c95..dd5e65a9a 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
@@ -32,7 +32,7 @@ import com.iluwatar.eda.model.User;
*/
public class UserCreatedEvent extends AbstractEvent {
- private User user;
+ private final User user;
public UserCreatedEvent(User user) {
this.user = user;
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
index 59583053c..05370c6a6 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
@@ -32,7 +32,7 @@ import com.iluwatar.eda.model.User;
*/
public class UserUpdatedEvent extends AbstractEvent {
- private User user;
+ private final User user;
public UserUpdatedEvent(User user) {
this.user = user;
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
index dd72c1e93..74a7ee145 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class EventDispatcher {
- private Map, Handler extends Event>> handlers;
+ private final Map, Handler extends Event>> handlers;
public EventDispatcher() {
handlers = new HashMap<>();
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
index 1492c175c..0c9f12501 100644
--- a/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
@@ -32,7 +32,7 @@ import com.iluwatar.eda.event.UserUpdatedEvent;
*/
public class User {
- private String username;
+ private final String username;
public User(String username) {
this.username = username;
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 4286a5ed0..a0ff5d987 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
@@ -49,7 +49,7 @@ public class Audio {
private volatile Thread updateThread = null;
- private PlayMessage[] pendingAudio = new PlayMessage[MAX_PENDING];
+ private final PlayMessage[] pendingAudio = new PlayMessage[MAX_PENDING];
// Visible only for testing purposes
Audio() {
diff --git a/event-sourcing/README.md b/event-sourcing/README.md
index 5efbbbd02..6d24a40e5 100644
--- a/event-sourcing/README.md
+++ b/event-sourcing/README.md
@@ -5,7 +5,8 @@ folder: event-sourcing
permalink: /patterns/event-sourcing/
categories: Architectural
tags:
- - Performance
+ - Performance
+ - Cloud distributed
---
## Intent
@@ -30,3 +31,4 @@ Use the Event Sourcing pattern when
* [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)
+* [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/module-info.java b/execute-around/src/main/java/com/iluwatar/execute/around/module-info.java
deleted file mode 100644
index a3e179094..000000000
--- a/execute-around/src/main/java/com/iluwatar/execute/around/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.executearound {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/extension-objects/src/main/java/concreteextensions/Commander.java b/extension-objects/src/main/java/concreteextensions/Commander.java
index 5a0552b20..1d8054562 100644
--- a/extension-objects/src/main/java/concreteextensions/Commander.java
+++ b/extension-objects/src/main/java/concreteextensions/Commander.java
@@ -35,7 +35,7 @@ public class Commander implements CommanderExtension {
private static final Logger LOGGER = LoggerFactory.getLogger(Commander.class);
- private CommanderUnit unit;
+ private final 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
index a45b82f11..4f5a474b3 100644
--- a/extension-objects/src/main/java/concreteextensions/Sergeant.java
+++ b/extension-objects/src/main/java/concreteextensions/Sergeant.java
@@ -35,7 +35,7 @@ public class Sergeant implements SergeantExtension {
private static final Logger LOGGER = LoggerFactory.getLogger(Sergeant.class);
- private SergeantUnit unit;
+ private final SergeantUnit unit;
public Sergeant(SergeantUnit sergeantUnit) {
this.unit = sergeantUnit;
diff --git a/extension-objects/src/main/java/concreteextensions/Soldier.java b/extension-objects/src/main/java/concreteextensions/Soldier.java
index b47ba595d..d500ab604 100644
--- a/extension-objects/src/main/java/concreteextensions/Soldier.java
+++ b/extension-objects/src/main/java/concreteextensions/Soldier.java
@@ -34,7 +34,7 @@ import units.SoldierUnit;
public class Soldier implements SoldierExtension {
private static final Logger LOGGER = LoggerFactory.getLogger(Soldier.class);
- private SoldierUnit unit;
+ private final SoldierUnit unit;
public Soldier(SoldierUnit soldierUnit) {
this.unit = soldierUnit;
diff --git a/facade/README.md b/facade/README.md
index 018c493a7..ce9d892b6 100644
--- a/facade/README.md
+++ b/facade/README.md
@@ -83,7 +83,7 @@ public abstract class DwarvenMineWorker {
public abstract String name();
- static enum Action {
+ enum Action {
GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
}
}
diff --git a/facade/src/main/java/com/iluwatar/facade/module-info.java b/facade/src/main/java/com/iluwatar/facade/module-info.java
deleted file mode 100644
index 966758790..000000000
--- a/facade/src/main/java/com/iluwatar/facade/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.facade {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
index 3b67f3754..10d6e1ecd 100644
--- a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
+++ b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
@@ -110,7 +110,7 @@ public class DwarvenGoldmineFacadeTest {
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/module-info.java b/factory-kit/src/main/java/com/iluwatar/factorykit/module-info.java
deleted file mode 100644
index 9440571c4..000000000
--- a/factory-kit/src/main/java/com/iluwatar/factorykit/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.factorykit {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java
index b6f29e43a..99ebcef65 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class ElfBlacksmith implements Blacksmith {
- private static Map ELFARSENAL;
+ private static final Map ELFARSENAL;
static {
ELFARSENAL = new HashMap<>(WeaponType.values().length);
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java
index 66a6ea7e7..208dfa277 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java
@@ -28,7 +28,7 @@ package com.iluwatar.factory.method;
*/
public class ElfWeapon implements Weapon {
- private WeaponType weaponType;
+ private final WeaponType weaponType;
public ElfWeapon(WeaponType weaponType) {
this.weaponType = weaponType;
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java
index b04830085..ea99200de 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class OrcBlacksmith implements Blacksmith {
- private static Map ORCARSENAL;
+ private static final Map ORCARSENAL;
static {
ORCARSENAL = new HashMap<>(WeaponType.values().length);
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java
index b35adf798..af1ee5bcf 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java
@@ -28,7 +28,7 @@ package com.iluwatar.factory.method;
*/
public class OrcWeapon implements Weapon {
- private WeaponType weaponType;
+ private final WeaponType weaponType;
public OrcWeapon(WeaponType weaponType) {
this.weaponType = weaponType;
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java b/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
index 73ab10dd6..6c7c86712 100644
--- a/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
@@ -30,7 +30,7 @@ public enum WeaponType {
SHORT_SWORD("short sword"), SPEAR("spear"), AXE("axe"), UNDEFINED("");
- private String title;
+ private final String title;
WeaponType(String title) {
this.title = title;
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/module-info.java b/factory-method/src/main/java/com/iluwatar/factory/method/module-info.java
deleted file mode 100644
index 4ea385c8b..000000000
--- a/factory-method/src/main/java/com/iluwatar/factory/method/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.factorymethod {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/module-info.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/module-info.java
deleted file mode 100644
index 55c2d7714..000000000
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/module-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-module com.iluwatar.featuretoggle {
- requires org.slf4j;
-}
\ No newline at end of file
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
index 6e2281b9a..ed6e69518 100644
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
@@ -42,7 +42,7 @@ import java.util.Properties;
*/
public class PropertiesFeatureToggleVersion implements Service {
- private boolean isEnhanced;
+ private final boolean isEnhanced;
/**
* Creates an instance of {@link PropertiesFeatureToggleVersion} using the passed {@link
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
index 5c660ca59..7924f86e8 100644
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
@@ -29,7 +29,7 @@ package com.iluwatar.featuretoggle.user;
*/
public class User {
- private String name;
+ private final String name;
/**
* Default Constructor setting the username.
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
index 524ea6ef8..7b644afd7 100644
--- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
@@ -35,8 +35,8 @@ import java.util.List;
*/
public class UserGroup {
- private static List freeGroup = new ArrayList<>();
- private static List paidGroup = new ArrayList<>();
+ private static final List freeGroup = new ArrayList<>();
+ private static final List paidGroup = new ArrayList<>();
/**
diff --git a/fluentinterface/README.md b/fluentinterface/README.md
index 3068468b9..61c5f2eb5 100644
--- a/fluentinterface/README.md
+++ b/fluentinterface/README.md
@@ -9,26 +9,151 @@ tags:
---
## Intent
-A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
+A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using
+this pattern results in code that can be read nearly as human language.
-## Implementation
+## Explanation
+The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those interfaces tend
+to mimic domain specific languages, so they can nearly be read as human languages.
+
A fluent interface can be implemented using any of
* Method Chaining - calling a method returns some object on which further methods can be called.
* Static Factory Methods and Imports
* Named parameters - can be simulated in Java using static factory methods.
+Real world example
+
+> We need to select numbers based on different criteria from the list. It's a great chance to utilize fluent interface pattern to provide readable easy-to-use developer experience.
+
+In plain words
+
+> Fluent Interface pattern provides easily readable flowing interface to code.
+
+Wikipedia says
+
+> In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL).
+
+**Programmatic Example**
+
+In this example two implementations of a `FluentIterable` interface are given.
+
+```java
+public interface FluentIterable extends Iterable {
+
+ FluentIterable filter(Predicate super E> predicate);
+
+ Optional first();
+
+ FluentIterable first(int count);
+
+ Optional last();
+
+ FluentIterable last(int count);
+
+ FluentIterable map(Function super E, T> function);
+
+ List asList();
+
+ static List copyToList(Iterable iterable) {
+ var copy = new ArrayList();
+ iterable.forEach(copy::add);
+ return copy;
+ }
+}
+```
+
+The `SimpleFluentIterable` evaluates eagerly and would be too costly for real world applications.
+
+```java
+public class SimpleFluentIterable implements FluentIterable {
+ ...
+}
+```
+
+The `LazyFluentIterable` is evaluated on termination.
+
+```java
+public class LazyFluentIterable implements FluentIterable {
+ ...
+}
+```
+
+Their usage is demonstrated with a simple number list that is filtered, transformed and collected. The
+result is printed afterwards.
+
+```java
+ var integerList = List.of(1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68);
+
+ prettyPrint("The initial list contains: ", integerList);
+
+ var firstFiveNegatives = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(negatives())
+ .first(3)
+ .asList();
+ prettyPrint("The first three negative values are: ", firstFiveNegatives);
+
+
+ var lastTwoPositives = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(positives())
+ .last(2)
+ .asList();
+ prettyPrint("The last two positive values are: ", lastTwoPositives);
+
+ SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(number -> number % 2 == 0)
+ .first()
+ .ifPresent(evenNumber -> LOGGER.info("The first even number is: {}", evenNumber));
+
+
+ var transformedList = SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(negatives())
+ .map(transformToString())
+ .asList();
+ prettyPrint("A string-mapped list of negative numbers contains: ", transformedList);
+
+
+ var lastTwoOfFirstFourStringMapped = LazyFluentIterable
+ .from(integerList)
+ .filter(positives())
+ .first(4)
+ .last(2)
+ .map(number -> "String[" + valueOf(number) + "]")
+ .asList();
+ prettyPrint("The lazy list contains the last two of the first four positive numbers "
+ + "mapped to Strings: ", lastTwoOfFirstFourStringMapped);
+
+ LazyFluentIterable
+ .from(integerList)
+ .filter(negatives())
+ .first(2)
+ .last()
+ .ifPresent(number -> LOGGER.info("Last amongst first two negatives: {}", number));
+
+ // The initial list contains: 1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68.
+ // The first three negative values are: -61, -22, -87.
+ // The last two positive values are: 23, 2.
+ // The first even number is: 14
+ // A string-mapped list of negative numbers contains: String[-61], String[-22], String[-87], String[-82], String[-98], String[-68].
+ // The lazy list contains the last two of the first four positive numbers mapped to Strings: String[18], String[6].
+ // Last amongst first two negatives: -22
+```
+
## Class diagram

## Applicability
Use the Fluent Interface pattern when
-* you provide an API that would benefit from a DSL-like usage
-* you have objects that are difficult to configure or use
+* You provide an API that would benefit from a DSL-like usage
+* You have objects that are difficult to configure or use
-## Real world examples
+## Known uses
* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html)
* [Google Guava FluentInterable](https://github.com/google/guava/wiki/FunctionalExplained)
@@ -41,3 +166,4 @@ Use the Fluent Interface pattern when
* [Fluent Interface - Martin Fowler](http://www.martinfowler.com/bliki/FluentInterface.html)
* [Evolutionary architecture and emergent design: Fluent interfaces - Neal Ford](http://www.ibm.com/developerworks/library/j-eaed14/)
* [Internal DSL](http://www.infoq.com/articles/internal-dsls-java)
+* [Domain Specific Languages](https://www.amazon.com/gp/product/0321712943/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=0321712943&linkId=ad8351d6f5be7d8b7ecdb650731f85df)
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 547c657e4..09513163c 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
@@ -94,7 +94,7 @@ public class App {
.filter(positives())
.first(4)
.last(2)
- .map(number -> "String[" + valueOf(number) + "]")
+ .map(number -> "String[" + number + "]")
.asList();
prettyPrint("The lazy list contains the last two of the first four positive numbers "
+ "mapped to Strings: ", lastTwoOfFirstFourStringMapped);
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
index f001c532f..966f35287 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
@@ -198,7 +198,7 @@ public class LazyFluentIterable implements FluentIterable {
@Override
public Iterator iterator() {
return new DecoratingIterator(null) {
- Iterator oldTypeIterator = iterable.iterator();
+ final Iterator oldTypeIterator = iterable.iterator();
@Override
public T computeNext() {
diff --git a/flux/src/main/java/com/iluwatar/flux/action/Action.java b/flux/src/main/java/com/iluwatar/flux/action/Action.java
index 6a5f608c2..c8e2e012b 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/Action.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/Action.java
@@ -28,7 +28,7 @@ package com.iluwatar.flux.action;
*/
public abstract class Action {
- private ActionType type;
+ private final ActionType type;
public Action(ActionType type) {
this.type = type;
diff --git a/flux/src/main/java/com/iluwatar/flux/action/ActionType.java b/flux/src/main/java/com/iluwatar/flux/action/ActionType.java
index 6399d2806..e84954efd 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/ActionType.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/ActionType.java
@@ -28,6 +28,6 @@ package com.iluwatar.flux.action;
*/
public enum ActionType {
- MENU_ITEM_SELECTED, CONTENT_CHANGED;
+ MENU_ITEM_SELECTED, CONTENT_CHANGED
}
diff --git a/flux/src/main/java/com/iluwatar/flux/action/Content.java b/flux/src/main/java/com/iluwatar/flux/action/Content.java
index 59a63ec18..6fb2e3e0e 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/Content.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/Content.java
@@ -31,7 +31,7 @@ public enum Content {
PRODUCTS("Products - This page lists the company's products."), COMPANY(
"Company - This page displays information about the company.");
- private String title;
+ private final String title;
Content(String title) {
this.title = title;
diff --git a/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java b/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java
index 3b29b6b4e..c70561a65 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/ContentAction.java
@@ -28,7 +28,7 @@ package com.iluwatar.flux.action;
*/
public class ContentAction extends Action {
- private Content content;
+ private final Content content;
public ContentAction(Content content) {
super(ActionType.CONTENT_CHANGED);
diff --git a/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java b/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java
index 5ddeefde4..f833a6187 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/MenuAction.java
@@ -29,7 +29,7 @@ package com.iluwatar.flux.action;
*/
public class MenuAction extends Action {
- private MenuItem menuItem;
+ private final MenuItem menuItem;
public MenuAction(MenuItem menuItem) {
super(ActionType.MENU_ITEM_SELECTED);
diff --git a/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java b/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java
index f251e1dd7..90fac3e2e 100644
--- a/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java
+++ b/flux/src/main/java/com/iluwatar/flux/action/MenuItem.java
@@ -30,7 +30,7 @@ public enum MenuItem {
HOME("Home"), PRODUCTS("Products"), COMPANY("Company");
- private String title;
+ private final String title;
MenuItem(String title) {
this.title = title;
diff --git a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
index cf09ecf68..27d374f5d 100644
--- a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
+++ b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
@@ -39,7 +39,7 @@ public final class Dispatcher {
private static Dispatcher instance = new Dispatcher();
- private List stores = new LinkedList<>();
+ private final List stores = new LinkedList<>();
private Dispatcher() {
}
diff --git a/flux/src/main/java/com/iluwatar/flux/store/Store.java b/flux/src/main/java/com/iluwatar/flux/store/Store.java
index cfbdf4af5..34188fff2 100644
--- a/flux/src/main/java/com/iluwatar/flux/store/Store.java
+++ b/flux/src/main/java/com/iluwatar/flux/store/Store.java
@@ -33,7 +33,7 @@ import java.util.List;
*/
public abstract class Store {
- private List views = new LinkedList<>();
+ private final List views = new LinkedList<>();
public abstract void onAction(Action action);
diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
index 4fa7312e5..e7af8ee00 100644
--- a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
+++ b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
@@ -34,8 +34,8 @@ public class AlchemistShop {
private static final Logger LOGGER = LoggerFactory.getLogger(AlchemistShop.class);
- private List topShelf;
- private List bottomShelf;
+ private final List topShelf;
+ private final List bottomShelf;
/**
* Constructor.
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 57cfb2454..8cbf7c631 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
@@ -36,7 +36,7 @@ import java.util.List;
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/game-loop/README.md b/game-loop/README.md
index f0a7eeebb..5f2cd9653 100644
--- a/game-loop/README.md
+++ b/game-loop/README.md
@@ -9,33 +9,227 @@ tags:
---
## Intent
-A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates the game state, and renders the game. It tracks the passage of time to control the rate of gameplay.
+A game loop runs continuously during gameplay. Each turn of the loop, it processes user input without blocking, updates
+the game state, and renders the game. It tracks the passage of time to control the rate of gameplay.
-This pattern decouple the progression of game time from user input and processor speed.
+This pattern decouples progression of game time from user input and processor speed.
## Applicability
This pattern is used in every game engine.
## Explanation
-Game loop is the main process of all the game rendering threads. It drives input process, internal status update, rendering, AI and all the other processes.
+Real world example
-There are a lot of implementations of game loop:
+> Game loop is the main process of all the game rendering threads. It's present in all modern games. It drives input process, internal status update, rendering, AI and all the other processes.
-- Frame-based game loop
+In plain words
-Frame-based game loop is the easiest implementation. The loop always keeps spinning for the following three processes: processInput, update and render. The problem with it is you have no control over how fast the game runs. On a fast machine, that loop will spin so fast users won’t be able to see what’s going on. On a slow machine, the game will crawl. If you have a part of the game that’s content-heavy or does more AI or physics, the game will actually play slower there.
+> Game Loop pattern ensures that game time progresses in equal speed in all different hardware setups.
-- Variable-step game loop
+Wikipedia says
-The variable-step game loop chooses a time step to advance based on how much real time passed since the last frame. The longer the frame takes, the bigger steps the game takes. It always keeps up with real time because it will take bigger and bigger steps to get there.
+> The central component of any game, from a programming standpoint, is the game loop. The game loop allows the game to run smoothly regardless of a user's input or lack thereof.
-- Fixed-step game loop
+**Programmatic Example**
-For fixed-step game loop, a certain amount of real time has elapsed since the last turn of the game loop. This is how much game time need to be simulated for the game’s “now” to catch up with the player’s.
+Let's start with something simple. Here's a bullet that will move in our game. For demonstration it's enough that it has 1-dimensional position.
+
+```java
+public class Bullet {
+
+ private float position;
+
+ public Bullet() {
+ position = 0.0f;
+ }
+
+ public float getPosition() {
+ return position;
+ }
+
+ public void setPosition(float position) {
+ this.position = position;
+ }
+}
+```
+
+GameController is responsible for moving objects in the game. Including the aforementioned bullet.
+
+```java
+public class GameController {
+
+ protected final Bullet bullet;
+
+ public GameController() {
+ bullet = new Bullet();
+ }
+
+ public void moveBullet(float offset) {
+ var currentPosition = bullet.getPosition();
+ bullet.setPosition(currentPosition + offset);
+ }
+
+ public float getBulletPosition() {
+ return bullet.getPosition();
+ }
+}
+```
+
+Now we introduce the game loop. Or actually in this demo we have 3 different game loops.
+
+```java
+public enum GameStatus {
+
+ RUNNING, STOPPED
+}
+
+public abstract class GameLoop {
+
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ protected volatile GameStatus status;
+
+ protected GameController controller;
+
+ private Thread gameThread;
+
+ public GameLoop() {
+ controller = new GameController();
+ status = GameStatus.STOPPED;
+ }
+
+ public void run() {
+ status = GameStatus.RUNNING;
+ gameThread = new Thread(() -> processGameLoop());
+ gameThread.start();
+ }
+
+ public void stop() {
+ status = GameStatus.STOPPED;
+ }
+
+ public boolean isGameRunning() {
+ return status == GameStatus.RUNNING;
+ }
+
+ protected void processInput() {
+ try {
+ var lag = new Random().nextInt(200) + 50;
+ Thread.sleep(lag);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+ protected void render() {
+ var position = controller.getBulletPosition();
+ logger.info("Current bullet position: " + position);
+ }
+
+ protected abstract void processGameLoop();
+}
+
+public class FrameBasedGameLoop extends GameLoop {
+
+ @Override
+ protected void processGameLoop() {
+ while (isGameRunning()) {
+ processInput();
+ update();
+ render();
+ }
+ }
+
+ protected void update() {
+ controller.moveBullet(0.5f);
+ }
+}
+
+public class VariableStepGameLoop extends GameLoop {
+
+ @Override
+ protected void processGameLoop() {
+ var lastFrameTime = System.currentTimeMillis();
+ while (isGameRunning()) {
+ processInput();
+ var currentFrameTime = System.currentTimeMillis();
+ var elapsedTime = currentFrameTime - lastFrameTime;
+ update(elapsedTime);
+ lastFrameTime = currentFrameTime;
+ render();
+ }
+ }
+
+ protected void update(Long elapsedTime) {
+ controller.moveBullet(0.5f * elapsedTime / 1000);
+ }
+}
+
+public class FixedStepGameLoop extends GameLoop {
+
+ private static final long MS_PER_FRAME = 20;
+
+ @Override
+ protected void processGameLoop() {
+ var previousTime = System.currentTimeMillis();
+ var lag = 0L;
+ while (isGameRunning()) {
+ var currentTime = System.currentTimeMillis();
+ var elapsedTime = currentTime - previousTime;
+ previousTime = currentTime;
+ lag += elapsedTime;
+
+ processInput();
+
+ while (lag >= MS_PER_FRAME) {
+ update();
+ lag -= MS_PER_FRAME;
+ }
+
+ render();
+ }
+ }
+
+ protected void update() {
+ controller.moveBullet(0.5f * MS_PER_FRAME / 1000);
+ }
+}
+```
+
+Finally we can show all these game loops in action.
+
+```java
+ try {
+ LOGGER.info("Start frame-based game loop:");
+ var frameBasedGameLoop = new FrameBasedGameLoop();
+ frameBasedGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ frameBasedGameLoop.stop();
+ LOGGER.info("Stop frame-based game loop.");
+
+ LOGGER.info("Start variable-step game loop:");
+ var variableStepGameLoop = new VariableStepGameLoop();
+ variableStepGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ variableStepGameLoop.stop();
+ LOGGER.info("Stop variable-step game loop.");
+
+ LOGGER.info("Start fixed-step game loop:");
+ var fixedStepGameLoop = new FixedStepGameLoop();
+ fixedStepGameLoop.run();
+ Thread.sleep(GAME_LOOP_DURATION_TIME);
+ fixedStepGameLoop.stop();
+ LOGGER.info("Stop variable-step game loop.");
+
+ } catch (InterruptedException e) {
+ LOGGER.error(e.getMessage());
+ }
+```
## Class diagram

## Credits
-
* [Game Programming Patterns - Game Loop](http://gameprogrammingpatterns.com/game-loop.html)
+* [Game Programming Patterns](https://www.amazon.com/gp/product/0990582906/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0990582906&linkId=1289749a703b3fe0e24cd8d604d7c40b)
+* [Game Engine Architecture, Third Edition](https://www.amazon.com/gp/product/1138035459/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1138035459&linkId=94502746617211bc40e0ef49d29333ac)
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 7df2264ab..d013924cb 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
@@ -95,7 +95,7 @@ public class App {
* ArithmeticSumTask.
*/
static class ArithmeticSumTask implements AsyncTask {
- private long numberOfElements;
+ private final long numberOfElements;
public ArithmeticSumTask(long numberOfElements) {
this.numberOfElements = numberOfElements;
diff --git a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java
index 3a3bb474c..32f5e9d4a 100644
--- a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java
+++ b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/AsynchronousService.java
@@ -48,7 +48,7 @@ public class AsynchronousService {
* tasks should be performed in the background which does not affect the performance of main
* thread.
*/
- private ExecutorService service;
+ private final ExecutorService service;
/**
* Creates an asynchronous service using {@code workQueue} as communication channel between
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java
index 1a0fdb6b0..746b93508 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/banking/InMemoryBank.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class InMemoryBank implements WireTransfers {
- private static Map accounts = new HashMap<>();
+ private static final Map accounts = new HashMap<>();
static {
accounts
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java
index 973747acc..5c0461843 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/database/InMemoryTicketRepository.java
@@ -34,7 +34,7 @@ import java.util.Optional;
*/
public class InMemoryTicketRepository implements LotteryTicketRepository {
- private static Map tickets = new HashMap<>();
+ private static final Map tickets = new HashMap<>();
@Override
public Optional findById(LotteryTicketId id) {
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 8988bba88..acdd2b8c5 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryNumbers.java
@@ -116,7 +116,7 @@ public class LotteryNumbers {
*/
private static class RandomNumberGenerator {
- private PrimitiveIterator.OfInt randomIterator;
+ private final PrimitiveIterator.OfInt randomIterator;
/**
* Initialize a new random number generator that generates random numbers in the range [min,
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 dfa324449..114e78c9c 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/domain/LotteryTicketId.java
@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class LotteryTicketId {
- private static AtomicInteger numAllocated = new AtomicInteger(0);
+ private static final AtomicInteger numAllocated = new AtomicInteger(0);
private final int id;
public LotteryTicketId() {
diff --git a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java
index ba46f2d97..c632debe8 100644
--- a/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java
+++ b/hexagonal/src/main/java/com/iluwatar/hexagonal/eventlog/MongoEventLog.java
@@ -41,7 +41,7 @@ public class MongoEventLog implements LotteryEventLog {
private MongoDatabase database;
private MongoCollection eventsCollection;
- private StdOutEventLog stdOutEventLog = new StdOutEventLog();
+ private final StdOutEventLog stdOutEventLog = new StdOutEventLog();
/**
* Constructor.
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 6d3ba8bc5..541b2b98b 100644
--- a/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java
+++ b/hexagonal/src/test/java/com/iluwatar/hexagonal/domain/LotteryTest.java
@@ -43,7 +43,7 @@ import org.junit.jupiter.api.Test;
*/
class LotteryTest {
- private Injector injector;
+ private final Injector injector;
@Inject
private LotteryAdministration administration;
@Inject
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 656008c10..52aa890c1 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
@@ -51,11 +51,11 @@ public class Client extends JFrame { // NOSONAR
private static final long serialVersionUID = 1L;
private transient FilterManager filterManager;
- private JLabel jl;
- private JTextField[] jtFields;
- private JTextArea[] jtAreas;
- private JButton clearButton;
- private JButton processButton;
+ private final JLabel jl;
+ private final JTextField[] jtFields;
+ private final JTextArea[] jtAreas;
+ private final JButton clearButton;
+ private final JButton processButton;
/**
* Constructor.
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
index e8f3b941f..91e438882 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
@@ -30,7 +30,7 @@ package com.iluwatar.intercepting.filter;
*/
public class FilterManager {
- private FilterChain filterChain;
+ private final FilterChain filterChain;
public FilterManager() {
filterChain = new FilterChain();
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 08ed715b1..db552356d 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
@@ -46,9 +46,9 @@ public class Target extends JFrame { //NOSONAR
private static final long serialVersionUID = 1L;
- private JTable jt;
- private DefaultTableModel dtm;
- private JButton del;
+ private final JTable jt;
+ private final DefaultTableModel dtm;
+ private final JButton del;
/**
* Constructor.
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java
index 24ef7914e..46b5c96cb 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/MinusExpression.java
@@ -28,8 +28,8 @@ package com.iluwatar.interpreter;
*/
public class MinusExpression extends Expression {
- private Expression leftExpression;
- private Expression rightExpression;
+ private final Expression leftExpression;
+ private final Expression rightExpression;
public MinusExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java
index 606937e0b..926d6c119 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/MultiplyExpression.java
@@ -28,8 +28,8 @@ package com.iluwatar.interpreter;
*/
public class MultiplyExpression extends Expression {
- private Expression leftExpression;
- private Expression rightExpression;
+ private final Expression leftExpression;
+ private final Expression rightExpression;
public MultiplyExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java
index 6b957f6aa..908eec8d1 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/NumberExpression.java
@@ -28,7 +28,7 @@ package com.iluwatar.interpreter;
*/
public class NumberExpression extends Expression {
- private int number;
+ private final int number;
public NumberExpression(int number) {
this.number = number;
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java b/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java
index 1ce080259..38a8bb4af 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/PlusExpression.java
@@ -28,8 +28,8 @@ package com.iluwatar.interpreter;
*/
public class PlusExpression extends Expression {
- private Expression leftExpression;
- private Expression rightExpression;
+ private final Expression leftExpression;
+ private final Expression rightExpression;
public PlusExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
diff --git a/iterator/README.md b/iterator/README.md
index 7f06a64b9..a98010c5a 100644
--- a/iterator/README.md
+++ b/iterator/README.md
@@ -36,7 +36,7 @@ The main class in our example is the treasure chest that contains items.
```java
public class TreasureChest {
- private List- items;
+ private final List
- items;
public TreasureChest() {
items = List.of(
@@ -64,7 +64,7 @@ public class TreasureChest {
public class Item {
private ItemType type;
- private String name;
+ private final String name;
public Item(ItemType type, String name) {
this.setType(type);
diff --git a/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java b/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java
index b3e0dc3d6..9f584cddc 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/bst/BstIterator.java
@@ -36,7 +36,7 @@ import java.util.NoSuchElementException;
*/
public class BstIterator
> implements Iterator> {
- private ArrayDeque> pathStack;
+ private final ArrayDeque> pathStack;
public BstIterator(TreeNode root) {
pathStack = new ArrayDeque<>();
diff --git a/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java b/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java
index 87f16e96c..b0ec5f486 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/bst/TreeNode.java
@@ -31,7 +31,7 @@ package com.iluwatar.iterator.bst;
*/
public class TreeNode> {
- private T val;
+ private final T val;
private TreeNode left;
private TreeNode right;
diff --git a/iterator/src/main/java/com/iluwatar/iterator/list/Item.java b/iterator/src/main/java/com/iluwatar/iterator/list/Item.java
index 82e66eb30..00d5625a8 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/list/Item.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/list/Item.java
@@ -29,7 +29,7 @@ package com.iluwatar.iterator.list;
public class Item {
private ItemType type;
- private String name;
+ private final String name;
public Item(ItemType type, String name) {
this.setType(type);
diff --git a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java
index f390c760f..8eb4a8e18 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChest.java
@@ -32,7 +32,7 @@ import java.util.List;
*/
public class TreasureChest {
- private List- items;
+ private final List
- items;
/**
* Constructor.
diff --git a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java
index 90461c420..a309b4ece 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/list/TreasureChestItemIterator.java
@@ -30,9 +30,9 @@ import com.iluwatar.iterator.Iterator;
*/
public class TreasureChestItemIterator implements Iterator
- {
- private TreasureChest chest;
+ private final TreasureChest chest;
private int idx;
- private ItemType type;
+ private final ItemType type;
/**
* Constructor.
diff --git a/layers/README.md b/layers/README.md
index c3c56ad00..1e309f92b 100644
--- a/layers/README.md
+++ b/layers/README.md
@@ -79,7 +79,7 @@ public class CakeViewImpl implements View {
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
- private CakeBakingService cakeBakingService;
+ private final CakeBakingService cakeBakingService;
public CakeViewImpl(CakeBakingService cakeBakingService) {
this.cakeBakingService = cakeBakingService;
diff --git a/layers/src/main/java/com/iluwatar/layers/app/App.java b/layers/src/main/java/com/iluwatar/layers/app/App.java
index afeb5ba50..e5a4f9995 100644
--- a/layers/src/main/java/com/iluwatar/layers/app/App.java
+++ b/layers/src/main/java/com/iluwatar/layers/app/App.java
@@ -80,7 +80,7 @@ import java.util.List;
*/
public class App {
- private static CakeBakingService cakeBakingService = new CakeBakingServiceImpl();
+ private static final CakeBakingService cakeBakingService = new CakeBakingServiceImpl();
/**
* Application entry point.
diff --git a/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java b/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java
index 226b5bcea..14fee4dfa 100644
--- a/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java
+++ b/layers/src/main/java/com/iluwatar/layers/service/CakeBakingServiceImpl.java
@@ -52,7 +52,7 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional
public class CakeBakingServiceImpl implements CakeBakingService {
- private AbstractApplicationContext context;
+ private final AbstractApplicationContext context;
public CakeBakingServiceImpl() {
this.context = new ClassPathXmlApplicationContext("applicationContext.xml");
diff --git a/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java b/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java
index 5fcaac776..a5246e7db 100644
--- a/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java
+++ b/layers/src/main/java/com/iluwatar/layers/view/CakeViewImpl.java
@@ -34,7 +34,7 @@ public class CakeViewImpl implements View {
private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
- private CakeBakingService cakeBakingService;
+ private final CakeBakingService cakeBakingService;
public CakeViewImpl(CakeBakingService cakeBakingService) {
this.cakeBakingService = cakeBakingService;
diff --git a/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java b/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java
index b707731d2..3c13966de 100644
--- a/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java
+++ b/layers/src/test/java/com/iluwatar/layers/view/CakeViewImplTest.java
@@ -90,7 +90,7 @@ public class CakeViewImplTest {
private class InMemoryAppender extends AppenderBase
{
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
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 2854a7822..395dfb81c 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
@@ -55,7 +55,7 @@ public class Java8Holder {
}
}
- if (!HeavyFactory.class.isInstance(heavy)) {
+ if (!(heavy instanceof HeavyFactory)) {
heavy = new HeavyFactory();
}
diff --git a/leader-election/README.md b/leader-election/README.md
index 3cfa7a662..85943d5b4 100644
--- a/leader-election/README.md
+++ b/leader-election/README.md
@@ -30,4 +30,4 @@ Do not use this pattern when
## Credits
-* [ Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn568104(v=pandp.10))
+* [Leader Election pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/leader-election)
diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java
index 3138427a3..3461bc8c0 100644
--- a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java
+++ b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/TaskSet.java
@@ -31,7 +31,7 @@ import java.util.concurrent.BlockingQueue;
*/
public class TaskSet {
- private BlockingQueue queue = new ArrayBlockingQueue<>(100);
+ private final BlockingQueue queue = new ArrayBlockingQueue<>(100);
public void addTask(Task task) throws InterruptedException {
queue.put(task);
diff --git a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java
index 7c63d95d2..935462037 100644
--- a/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java
+++ b/leader-followers/src/main/java/com.iluwatar.leaderfollowers/WorkCenter.java
@@ -34,7 +34,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
public class WorkCenter {
private Worker leader;
- private List workers = new CopyOnWriteArrayList<>();
+ private final List workers = new CopyOnWriteArrayList<>();
/**
* Create workers and set leader.
diff --git a/marker/src/main/java/App.java b/marker/src/main/java/App.java
index 384c999dc..0908503e5 100644
--- a/marker/src/main/java/App.java
+++ b/marker/src/main/java/App.java
@@ -46,17 +46,18 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
+ final var logger = LoggerFactory.getLogger(App.class);
+ var guard = new Guard();
+ var thief = new Thief();
- final Logger logger = LoggerFactory.getLogger(App.class);
- Guard guard = new Guard();
- Thief thief = new Thief();
-
+ //noinspection ConstantConditions
if (guard instanceof Permission) {
guard.enter();
} else {
logger.info("You have no permission to enter, please leave this area");
}
+ //noinspection ConstantConditions
if (thief instanceof Permission) {
thief.steal();
} else {
diff --git a/marker/src/main/java/Guard.java b/marker/src/main/java/Guard.java
index 9a57e15fd..9e7b731b6 100644
--- a/marker/src/main/java/Guard.java
+++ b/marker/src/main/java/Guard.java
@@ -28,11 +28,9 @@ import org.slf4j.LoggerFactory;
* Class defining Guard.
*/
public class Guard implements Permission {
-
private static final Logger LOGGER = LoggerFactory.getLogger(Guard.class);
- protected static void enter() {
-
+ protected void enter() {
LOGGER.info("You can enter");
}
}
diff --git a/marker/src/main/java/Thief.java b/marker/src/main/java/Thief.java
index 341eae377..0e4cf92e3 100644
--- a/marker/src/main/java/Thief.java
+++ b/marker/src/main/java/Thief.java
@@ -28,14 +28,13 @@ import org.slf4j.LoggerFactory;
* Class defining Thief.
*/
public class Thief {
-
private static final Logger LOGGER = LoggerFactory.getLogger(Thief.class);
- protected static void steal() {
+ protected void steal() {
LOGGER.info("Steal valuable items");
}
- protected static void doNothing() {
+ protected void doNothing() {
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 5d63db0ad..13295a9e5 100644
--- a/marker/src/test/java/AppTest.java
+++ b/marker/src/test/java/AppTest.java
@@ -30,7 +30,6 @@ public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/marker/src/test/java/GuardTest.java b/marker/src/test/java/GuardTest.java
index 615d4e129..ae92c27dc 100644
--- a/marker/src/test/java/GuardTest.java
+++ b/marker/src/test/java/GuardTest.java
@@ -33,7 +33,7 @@ public class GuardTest {
@Test
public void testGuard() {
- Guard guard = new Guard();
+ var 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 2732fc78a..dc081acf8 100644
--- a/marker/src/test/java/ThiefTest.java
+++ b/marker/src/test/java/ThiefTest.java
@@ -21,9 +21,11 @@
* THE SOFTWARE.
*/
-import org.junit.jupiter.api.Test;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertFalse;
+import org.junit.jupiter.api.Test;
/**
* Thief test
@@ -31,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
public class ThiefTest {
@Test
public void testThief() {
- Thief thief = new Thief();
- assertFalse(thief instanceof Permission);
+ var thief = new Thief();
+ assertThat(thief, not(instanceOf(Permission.class)));
}
}
\ No newline at end of file
diff --git a/master-worker-pattern/pom.xml b/master-worker-pattern/pom.xml
index 9924d6a5a..26f4d70bb 100644
--- a/master-worker-pattern/pom.xml
+++ b/master-worker-pattern/pom.xml
@@ -22,38 +22,39 @@
THE SOFTWARE.
-->
-
- 4.0.0
-
- com.iluwatar
- java-design-patterns
- 1.23.0-SNAPSHOT
-
- master-worker-pattern
-
-
- org.junit.jupiter
- junit-jupiter-engine
- test
-
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.23.0-SNAPSHOT
+
+ master-worker-pattern
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
-
-
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
-
-
-
- com.iluwatar.masterworker.App
-
-
-
-
-
-
-
-
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.masterworker.App
+
+
+
+
+
+
+
+
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/App.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/App.java
index 547636066..592ba8c59 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/App.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/App.java
@@ -34,27 +34,25 @@ import org.slf4j.LoggerFactory;
/**
* The Master-Worker pattern is used when the problem at hand can be solved by
- * dividing into
- * multiple parts which need to go through the same computation and may need to be aggregated to get
- * final result. Parallel processing is performed using a system consisting of a master and some
- * number of workers, where a master divides the work among the workers, gets the result back from
- * them and assimilates all the results to give final result. The only communication is between the
- * master and the worker - none of the workers communicate among one another and the user only
- * communicates with the master to get required job done.
+ * dividing into multiple parts which need to go through the same computation and may need to be
+ * aggregated to get final result. Parallel processing is performed using a system consisting of a
+ * master and some number of workers, where a master divides the work among the workers, gets the
+ * result back from them and assimilates all the results to give final result. The only
+ * communication is between the master and the worker - none of the workers communicate among one
+ * another and the user only communicates with the master to get required job done.
* In our example, we have generic abstract classes {@link MasterWorker}, {@link Master} and
- * {@link Worker} which
- * have to be extended by the classes which will perform the specific job at hand (in this case
- * finding transpose of matrix, done by {@link ArrayTransposeMasterWorker}, {@link
- * ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work into
- * parts to be given to the workers, collects the results from the workers and aggregates it when
- * all workers have responded before returning the solution. The Worker class extends the Thread
- * class to enable parallel processing, and does the work once the data has been received from the
- * Master. The MasterWorker contains a reference to the Master class, gets the input from the App
- * and passes it on to the Master. These 3 classes define the system which computes the result. We
- * also have 2 abstract classes {@link Input} and {@link Result}, which contain the input data and
- * result data respectively. The Input class also has an abstract method divideData which defines
- * how the data is to be divided into segments. These classes are extended by {@link ArrayInput} and
- * {@link ArrayResult}.
+ * {@link Worker} which have to be extended by the classes which will perform the specific job at
+ * hand (in this case finding transpose of matrix, done by {@link ArrayTransposeMasterWorker},
+ * {@link ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work
+ * into parts to be given to the workers, collects the results from the workers and aggregates it
+ * when all workers have responded before returning the solution. The Worker class extends the
+ * Thread class to enable parallel processing, and does the work once the data has been received
+ * from the Master. The MasterWorker contains a reference to the Master class, gets the input from
+ * the App and passes it on to the Master. These 3 classes define the system which computes the
+ * result. We also have 2 abstract classes {@link Input} and {@link Result}, which contain the input
+ * data and result data respectively. The Input class also has an abstract method divideData which
+ * defines how the data is to be divided into segments. These classes are extended by {@link
+ * ArrayInput} and {@link ArrayResult}.
*/
public class App {
@@ -68,12 +66,12 @@ public class App {
*/
public static void main(String[] args) {
- ArrayTransposeMasterWorker mw = new ArrayTransposeMasterWorker();
- int rows = 10;
- int columns = 20;
- int[][] inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
- ArrayInput input = new ArrayInput(inputMatrix);
- ArrayResult result = (ArrayResult) mw.getResult(input);
+ var mw = new ArrayTransposeMasterWorker();
+ var rows = 10;
+ var columns = 20;
+ var inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
+ var input = new ArrayInput(inputMatrix);
+ var result = (ArrayResult) mw.getResult(input);
if (result != null) {
ArrayUtilityMethods.printMatrix(inputMatrix);
ArrayUtilityMethods.printMatrix(result.data);
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java
index cd03a0a21..c8e68f958 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayInput.java
@@ -25,6 +25,7 @@ package com.iluwatar.masterworker;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Class ArrayInput extends abstract class {@link Input} and contains data of type int[][].
@@ -37,12 +38,12 @@ public class ArrayInput extends Input {
}
static int[] makeDivisions(int[][] data, int num) {
- int initialDivision = data.length / num; //equally dividing
- int[] divisions = new int[num];
+ var initialDivision = data.length / num; //equally dividing
+ var divisions = new int[num];
Arrays.fill(divisions, initialDivision);
if (initialDivision * num != data.length) {
- int extra = data.length - initialDivision * num;
- int l = 0;
+ var extra = data.length - initialDivision * num;
+ var l = 0;
//equally dividing extra among all parts
while (extra > 0) {
divisions[l] = divisions[l] + 1;
@@ -58,22 +59,20 @@ public class ArrayInput extends Input {
}
@Override
- public ArrayList divideData(int num) {
+ public List > divideData(int num) {
if (this.data == null) {
return null;
} else {
- int[] divisions = makeDivisions(this.data, num);
- ArrayList result = new ArrayList (num);
- int rowsDone = 0; //number of rows divided so far
- for (int i = 0; i < num; i++) {
- int rows = divisions[i];
+ var divisions = makeDivisions(this.data, num);
+ var result = new ArrayList >(num);
+ var rowsDone = 0; //number of rows divided so far
+ for (var i = 0; i < num; i++) {
+ var rows = divisions[i];
if (rows != 0) {
- int[][] divided = new int[rows][this.data[0].length];
- for (int j = 0; j < rows; j++) {
- divided[j] = this.data[rowsDone + j];
- }
+ var divided = new int[rows][this.data[0].length];
+ System.arraycopy(this.data, rowsDone, divided, 0, rows);
rowsDone += rows;
- ArrayInput dividedInput = new ArrayInput(divided);
+ var dividedInput = new ArrayInput(divided);
result.add(dividedInput);
} else {
break; //rest of divisions will also be 0
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java
index 525bed003..5e695e5da 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/ArrayUtilityMethods.java
@@ -47,8 +47,8 @@ public class ArrayUtilityMethods {
if (a1.length != a2.length) {
return false;
} else {
- boolean answer = false;
- for (int i = 0; i < a1.length; i++) {
+ var answer = false;
+ for (var i = 0; i < a1.length; i++) {
if (a1[i] == a2[i]) {
answer = true;
} else {
@@ -69,8 +69,8 @@ public class ArrayUtilityMethods {
if (m1.length != m2.length) {
return false;
} else {
- boolean answer = false;
- for (int i = 0; i < m1.length; i++) {
+ var answer = false;
+ for (var i = 0; i < m1.length; i++) {
if (arraysSame(m1[i], m2[i])) {
answer = true;
} else {
@@ -88,9 +88,9 @@ public class ArrayUtilityMethods {
* @return it (int[][]).
*/
public static int[][] createRandomIntMatrix(int rows, int columns) {
- int[][] matrix = new int[rows][columns];
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < columns; j++) {
+ var matrix = new int[rows][columns];
+ for (var i = 0; i < rows; i++) {
+ for (var j = 0; j < columns; j++) {
//filling cells in matrix
matrix[i][j] = RANDOM.nextInt(10);
}
@@ -104,9 +104,9 @@ public class ArrayUtilityMethods {
public static void printMatrix(int[][] matrix) {
//prints out int[][]
- for (int i = 0; i < matrix.length; i++) {
- for (int j = 0; j < matrix[0].length; j++) {
- LOGGER.info(matrix[i][j] + " ");
+ for (var ints : matrix) {
+ for (var j = 0; j < matrix[0].length; j++) {
+ LOGGER.info(ints[j] + " ");
}
LOGGER.info("");
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java
index 6a957ae80..8d832f6c7 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/Input.java
@@ -23,7 +23,7 @@
package com.iluwatar.masterworker;
-import java.util.ArrayList;
+import java.util.List;
/**
* The abstract Input class, having 1 public field which contains input data, and abstract method
@@ -40,5 +40,5 @@ public abstract class Input {
this.data = data;
}
- public abstract ArrayList divideData(int num);
+ public abstract List > divideData(int num);
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java
index 2b16cbf76..817fd65d3 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/MasterWorker.java
@@ -40,7 +40,7 @@ public abstract class MasterWorker {
abstract Master setMaster(int numOfWorkers);
- public Result getResult(Input input) {
+ public Result> getResult(Input> input) {
this.master.doWork(input);
return this.master.getFinalResult();
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java
index ffa64572c..9bfbf200e 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/ArrayTransposeMaster.java
@@ -27,7 +27,8 @@ import com.iluwatar.masterworker.ArrayResult;
import com.iluwatar.masterworker.system.systemworkers.ArrayTransposeWorker;
import com.iluwatar.masterworker.system.systemworkers.Worker;
import java.util.ArrayList;
-import java.util.Enumeration;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Class ArrayTransposeMaster extends abstract class {@link Master} and contains definition of
@@ -41,35 +42,33 @@ public class ArrayTransposeMaster extends Master {
@Override
ArrayList setWorkers(int num) {
- ArrayList ws = new ArrayList(num);
- for (int i = 0; i < num; i++) {
- ws.add(new ArrayTransposeWorker(this, i + 1));
- //i+1 will be id
- }
- return ws;
+ //i+1 will be id
+ return IntStream.range(0, num)
+ .mapToObj(i -> new ArrayTransposeWorker(this, i + 1))
+ .collect(Collectors.toCollection(() -> new ArrayList<>(num)));
}
@Override
ArrayResult aggregateData() {
// number of rows in final result is number of rows in any of obtained results from workers
- int rows = ((ArrayResult) this.getAllResultData()
- .get(this.getAllResultData().keys().nextElement())).data.length;
- int columns =
- 0; //number of columns is sum of number of columns in all results obtained from workers
- for (Enumeration e = this.getAllResultData().keys(); e.hasMoreElements(); ) {
- columns += ((ArrayResult) this.getAllResultData().get(e.nextElement())).data[0].length;
+ var allResultData = this.getAllResultData();
+ var rows = ((ArrayResult) allResultData.elements().nextElement()).data.length;
+ var elements = allResultData.elements();
+ var columns = 0; // columns = sum of number of columns in all results obtained from workers
+ while (elements.hasMoreElements()) {
+ columns += ((ArrayResult) elements.nextElement()).data[0].length;
}
- int[][] resultData = new int[rows][columns];
- int columnsDone = 0; //columns aggregated so far
- for (int i = 0; i < this.getExpectedNumResults(); i++) {
+ var resultData = new int[rows][columns];
+ var columnsDone = 0; //columns aggregated so far
+ var workers = this.getWorkers();
+ for (var i = 0; i < this.getExpectedNumResults(); i++) {
//result obtained from ith worker
- int[][] work =
- ((ArrayResult) this.getAllResultData().get(this.getWorkers().get(i).getWorkerId())).data;
- for (int m = 0; m < work.length; m++) {
+ var worker = workers.get(i);
+ var workerId = worker.getWorkerId();
+ var work = ((ArrayResult) allResultData.get(workerId)).data;
+ for (var m = 0; m < work.length; m++) {
//m = row number, n = columns number
- for (int n = 0; n < work[0].length; n++) {
- resultData[m][columnsDone + n] = work[m][n];
- }
+ System.arraycopy(work[m], 0, resultData[m], columnsDone, work[0].length);
}
columnsDone += work[0].length;
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java
index 2466df256..06ea3a8fe 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemmaster/Master.java
@@ -26,8 +26,8 @@ package com.iluwatar.masterworker.system.systemmaster;
import com.iluwatar.masterworker.Input;
import com.iluwatar.masterworker.Result;
import com.iluwatar.masterworker.system.systemworkers.Worker;
-import java.util.ArrayList;
import java.util.Hashtable;
+import java.util.List;
/**
* The abstract Master class which contains private fields numOfWorkers (number of workers), workers
@@ -38,24 +38,24 @@ import java.util.Hashtable;
public abstract class Master {
private final int numOfWorkers;
- private final ArrayList workers;
+ private final List workers;
+ private final Hashtable> allResultData;
private int expectedNumResults;
- private Hashtable allResultData;
- private Result finalResult;
+ private Result> finalResult;
Master(int numOfWorkers) {
this.numOfWorkers = numOfWorkers;
this.workers = setWorkers(numOfWorkers);
this.expectedNumResults = 0;
- this.allResultData = new Hashtable(numOfWorkers);
+ this.allResultData = new Hashtable<>(numOfWorkers);
this.finalResult = null;
}
- public Result getFinalResult() {
+ public Result> getFinalResult() {
return this.finalResult;
}
- Hashtable getAllResultData() {
+ Hashtable> getAllResultData() {
return this.allResultData;
}
@@ -63,34 +63,41 @@ public abstract class Master {
return this.expectedNumResults;
}
- ArrayList getWorkers() {
+ List getWorkers() {
return this.workers;
}
- abstract ArrayList setWorkers(int num);
+ abstract List setWorkers(int num);
- public void doWork(Input input) {
+ public void doWork(Input> input) {
divideWork(input);
}
- private void divideWork(Input input) {
- ArrayList dividedInput = input.divideData(numOfWorkers);
+ private void divideWork(Input> input) {
+ var dividedInput = input.divideData(numOfWorkers);
if (dividedInput != null) {
this.expectedNumResults = dividedInput.size();
- for (int i = 0; i < this.expectedNumResults; i++) {
+ for (var i = 0; i < this.expectedNumResults; i++) {
//ith division given to ith worker in this.workers
this.workers.get(i).setReceivedData(this, dividedInput.get(i));
- this.workers.get(i).run();
+ this.workers.get(i).start();
+ }
+ for (var i = 0; i < this.expectedNumResults; i++) {
+ try {
+ this.workers.get(i).join();
+ } catch (InterruptedException e) {
+ System.err.println("Error while executing thread");
+ }
}
}
}
- public void receiveData(Result data, Worker w) {
+ public void receiveData(Result> data, Worker w) {
//check if can receive..if yes:
collectResult(data, w.getWorkerId());
}
- private void collectResult(Result data, int workerId) {
+ private void collectResult(Result> data, int workerId) {
this.allResultData.put(workerId, data);
if (this.allResultData.size() == this.expectedNumResults) {
//all data received
@@ -98,5 +105,5 @@ public abstract class Master {
}
}
- abstract Result aggregateData();
+ abstract Result> aggregateData();
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java
index 37d8ba005..3f2da0a0a 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorker.java
@@ -41,12 +41,12 @@ public class ArrayTransposeWorker extends Worker {
@Override
ArrayResult executeOperation() {
//number of rows in result matrix is equal to number of columns in input matrix and vice versa
- ArrayInput arrayInput = (ArrayInput) this.getReceivedData();
- final int rows = arrayInput.data[0].length;
- final int cols = arrayInput.data.length;
- int[][] resultData = new int[rows][cols];
- for (int i = 0; i < cols; i++) {
- for (int j = 0; j < rows; j++) {
+ var arrayInput = (ArrayInput) this.getReceivedData();
+ final var rows = arrayInput.data[0].length;
+ final var cols = arrayInput.data.length;
+ var resultData = new int[rows][cols];
+ for (var i = 0; i < cols; i++) {
+ for (var j = 0; j < rows; j++) {
//flipping element positions along diagonal
resultData[j][i] = arrayInput.data[i][j];
}
diff --git a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java
index bfe226ee0..526299645 100644
--- a/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java
+++ b/master-worker-pattern/src/main/java/com/iluwatar/masterworker/system/systemworkers/Worker.java
@@ -35,7 +35,7 @@ import com.iluwatar.masterworker.system.systemmaster.Master;
public abstract class Worker extends Thread {
private final Master master;
private final int workerId;
- private Input receivedData;
+ private Input> receivedData;
Worker(Master master, int id) {
this.master = master;
@@ -47,23 +47,23 @@ public abstract class Worker extends Thread {
return this.workerId;
}
- Input getReceivedData() {
+ Input> getReceivedData() {
return this.receivedData;
}
- public void setReceivedData(Master m, Input i) {
+ public void setReceivedData(Master m, Input> i) {
//check if ready to receive..if yes:
this.receivedData = i;
}
- abstract Result executeOperation();
+ abstract Result> executeOperation();
- private void sendToMaster(Result data) {
+ private void sendToMaster(Result> data) {
this.master.receiveData(data, this);
}
public void run() { //from Thread class
- Result work = executeOperation();
+ var work = executeOperation();
sendToMaster(work);
}
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java
index b5820e2af..1d3c7f0bc 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayInputTest.java
@@ -23,38 +23,39 @@
package com.iluwatar.masterworker;
-import static org.junit.jupiter.api.Assertions.*;
-import java.util.ArrayList;
+import static com.iluwatar.masterworker.ArrayUtilityMethods.matricesSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import java.util.Random;
import org.junit.jupiter.api.Test;
/**
-* Testing divideData method in {@link ArrayInput} class.
-*/
+ * Testing divideData method in {@link ArrayInput} class.
+ */
class ArrayInputTest {
@Test
void divideDataTest() {
- int rows = 10;
- int columns = 10;
- int[][] inputMatrix = new int[rows][columns];
- Random rand = new Random();
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < columns; j++) {
+ var rows = 10;
+ var columns = 10;
+ var inputMatrix = new int[rows][columns];
+ var rand = new Random();
+ for (var i = 0; i < rows; i++) {
+ for (var j = 0; j < columns; j++) {
inputMatrix[i][j] = rand.nextInt(10);
}
}
- ArrayInput i = new ArrayInput(inputMatrix);
- ArrayList table = i.divideData(4);
- int[][] division1 = new int[][] {inputMatrix[0], inputMatrix[1], inputMatrix[2]};
- int[][] division2 = new int[][] {inputMatrix[3], inputMatrix[4], inputMatrix[5]};
- int[][] division3 = new int[][] {inputMatrix[6], inputMatrix[7]};
- int[][] division4 = new int[][] {inputMatrix[8], inputMatrix[9]};
- assertTrue(ArrayUtilityMethods.matricesSame((int[][]) table.get(0).data, division1)
- && ArrayUtilityMethods.matricesSame((int[][]) table.get(1).data, division2)
- && ArrayUtilityMethods.matricesSame((int[][]) table.get(2).data, division3)
- && ArrayUtilityMethods.matricesSame((int[][]) table.get(3).data, division4));
+ var i = new ArrayInput(inputMatrix);
+ var table = i.divideData(4);
+ var division1 = new int[][]{inputMatrix[0], inputMatrix[1], inputMatrix[2]};
+ var division2 = new int[][]{inputMatrix[3], inputMatrix[4], inputMatrix[5]};
+ var division3 = new int[][]{inputMatrix[6], inputMatrix[7]};
+ var division4 = new int[][]{inputMatrix[8], inputMatrix[9]};
+ assertTrue(matricesSame(table.get(0).data, division1)
+ && matricesSame(table.get(1).data, division2)
+ && matricesSame(table.get(2).data, division3)
+ && matricesSame(table.get(3).data, division4));
}
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java
index aae784b52..d25276572 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/ArrayUtilityMethodsTest.java
@@ -23,27 +23,27 @@
package com.iluwatar.masterworker;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
-* Testing utility methods in {@link ArrayUtilityMethods} class.
-*/
+ * Testing utility methods in {@link ArrayUtilityMethods} class.
+ */
class ArrayUtilityMethodsTest {
@Test
void arraysSameTest() {
- int[] arr1 = new int[] {1,4,2,6};
- int[] arr2 = new int[] {1,4,2,6};
+ var arr1 = new int[]{1, 4, 2, 6};
+ var arr2 = new int[]{1, 4, 2, 6};
assertTrue(ArrayUtilityMethods.arraysSame(arr1, arr2));
}
@Test
void matricesSameTest() {
- int[][] matrix1 = new int[][] {{1,4,2,6},{5,8,6,7}};
- int[][] matrix2 = new int[][] {{1,4,2,6},{5,8,6,7}};
+ var matrix1 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
+ var matrix2 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
assertTrue(ArrayUtilityMethods.matricesSame(matrix1, matrix2));
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java
index b80d7881f..79838ed35 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/ArrayTransposeMasterWorkerTest.java
@@ -23,25 +23,38 @@
package com.iluwatar.masterworker.system;
-import static org.junit.jupiter.api.Assertions.*;
-import org.junit.jupiter.api.Test;
-import com.iluwatar.masterworker.ArrayUtilityMethods;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import com.iluwatar.masterworker.ArrayInput;
import com.iluwatar.masterworker.ArrayResult;
+import com.iluwatar.masterworker.ArrayUtilityMethods;
+import org.junit.jupiter.api.Test;
/**
-* Testing getResult method in {@link ArrayTransposeMasterWorker} class.
-*/
+ * Testing getResult method in {@link ArrayTransposeMasterWorker} class.
+ */
class ArrayTransposeMasterWorkerTest {
@Test
void getResultTest() {
- ArrayTransposeMasterWorker atmw = new ArrayTransposeMasterWorker();
- int[][] matrix = new int[][] {{1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}};
- int[][] matrixTranspose = new int[][] {{1,1,1,1,1}, {2,2,2,2,2}, {3,3,3,3,3}, {4,4,4,4,4}, {5,5,5,5,5}};
- ArrayInput i = new ArrayInput(matrix);
- ArrayResult r = (ArrayResult) atmw.getResult(i);
+ var atmw = new ArrayTransposeMasterWorker();
+ var matrix = new int[][]{
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5},
+ {1, 2, 3, 4, 5}
+ };
+ var matrixTranspose = new int[][]{
+ {1, 1, 1, 1, 1},
+ {2, 2, 2, 2, 2},
+ {3, 3, 3, 3, 3},
+ {4, 4, 4, 4, 4},
+ {5, 5, 5, 5, 5}
+ };
+ var i = new ArrayInput(matrix);
+ var r = (ArrayResult) atmw.getResult(i);
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
- }
+ }
}
diff --git a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java
index 3e5f581b9..c4b210643 100644
--- a/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java
+++ b/master-worker-pattern/src/test/java/com/iluwatar/masterworker/system/systemworkers/ArrayTransposeWorkerTest.java
@@ -23,29 +23,29 @@
package com.iluwatar.masterworker.system.systemworkers;
-import static org.junit.jupiter.api.Assertions.*;
-import org.junit.jupiter.api.Test;
-import com.iluwatar.masterworker.ArrayUtilityMethods;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
import com.iluwatar.masterworker.ArrayInput;
-import com.iluwatar.masterworker.ArrayResult;
+import com.iluwatar.masterworker.ArrayUtilityMethods;
import com.iluwatar.masterworker.system.systemmaster.ArrayTransposeMaster;
+import org.junit.jupiter.api.Test;
/**
-* Testing executeOperation method in {@link ArrayTransposeWorker} class.
-*/
+ * Testing executeOperation method in {@link ArrayTransposeWorker} class.
+ */
class ArrayTransposeWorkerTest {
@Test
void executeOperationTest() {
- ArrayTransposeMaster atm = new ArrayTransposeMaster(1);
- ArrayTransposeWorker atw = new ArrayTransposeWorker(atm, 1);
- int[][] matrix = new int[][] {{2,4}, {3,5}};
- int[][] matrixTranspose = new int[][] {{2,3}, {4,5}};
- ArrayInput i = new ArrayInput(matrix);
+ var atm = new ArrayTransposeMaster(1);
+ var atw = new ArrayTransposeWorker(atm, 1);
+ var matrix = new int[][]{{2, 4}, {3, 5}};
+ var matrixTranspose = new int[][]{{2, 3}, {4, 5}};
+ var i = new ArrayInput(matrix);
atw.setReceivedData(atm, i);
- ArrayResult r = atw.executeOperation();
+ var r = atw.executeOperation();
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
}
-
+
}
diff --git a/mediator/src/main/java/com/iluwatar/mediator/Action.java b/mediator/src/main/java/com/iluwatar/mediator/Action.java
index 66e1f42c4..60ce3949a 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/Action.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/Action.java
@@ -1,52 +1,51 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.mediator;
-
-/**
- * Action enumeration.
- */
-public enum Action {
-
- HUNT("hunted a rabbit", "arrives for dinner"),
- TALE("tells a tale", "comes to listen"),
- GOLD("found gold", "takes his share of the gold"),
- ENEMY("spotted enemies", "runs for cover"),
- NONE("", "");
-
- private String title;
- private String description;
-
- Action(String title, String description) {
- this.title = title;
- this.description = description;
- }
-
- public String getDescription() {
- return description;
- }
-
- public String toString() {
- return title;
- }
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.mediator;
+
+/**
+ * Action enumeration.
+ */
+public enum Action {
+ HUNT("hunted a rabbit", "arrives for dinner"),
+ TALE("tells a tale", "comes to listen"),
+ GOLD("found gold", "takes his share of the gold"),
+ ENEMY("spotted enemies", "runs for cover"),
+ NONE("", "");
+
+ private final String title;
+ private final String description;
+
+ Action(String title, String description) {
+ this.title = title;
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String toString() {
+ return title;
+ }
+}
diff --git a/mediator/src/main/java/com/iluwatar/mediator/App.java b/mediator/src/main/java/com/iluwatar/mediator/App.java
index 9dbedb4ab..0e9021c0d 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/App.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/App.java
@@ -55,10 +55,10 @@ public class App {
// create party and members
Party party = new PartyImpl();
- Hobbit hobbit = new Hobbit();
- Wizard wizard = new Wizard();
- Rogue rogue = new Rogue();
- Hunter hunter = new Hunter();
+ var hobbit = new Hobbit();
+ var wizard = new Wizard();
+ var rogue = new Rogue();
+ var hunter = new Hunter();
// add party members
party.addMember(hobbit);
diff --git a/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java b/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
index 6384a2187..f842a0f39 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
@@ -39,7 +39,7 @@ public class PartyImpl implements Party {
@Override
public void act(PartyMember actor, Action action) {
- for (PartyMember member : members) {
+ for (var member : members) {
if (!member.equals(actor)) {
member.partyAction(action);
}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
index 3a55d51d8..23f2a72f2 100644
--- a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
+++ b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
@@ -26,15 +26,12 @@ package com.iluwatar.mediator;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java b/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
index 5d2446545..d25562f84 100644
--- a/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
+++ b/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
@@ -43,10 +43,10 @@ public class PartyImplTest {
*/
@Test
public void testPartyAction() {
- final PartyMember partyMember1 = mock(PartyMember.class);
- final PartyMember partyMember2 = mock(PartyMember.class);
+ final var partyMember1 = mock(PartyMember.class);
+ final var partyMember2 = mock(PartyMember.class);
- final PartyImpl party = new PartyImpl();
+ final var party = new PartyImpl();
party.addMember(partyMember1);
party.addMember(partyMember2);
@@ -58,7 +58,6 @@ public class PartyImplTest {
verify(partyMember2).partyAction(Action.GOLD);
verifyNoMoreInteractions(partyMember1, partyMember2);
-
}
}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
index 951f8e166..a0e722cfd 100644
--- a/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
+++ b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
@@ -23,24 +23,24 @@
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.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.function.Supplier;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+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.function.Supplier;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.slf4j.LoggerFactory;
+
/**
* Date: 12/19/15 - 10:13 PM
*
@@ -48,12 +48,12 @@ import static org.mockito.Mockito.verify;
*/
public class PartyMemberTest {
- static Collection[]> dataProvider() {
- return List.of(
- new Supplier[]{Hobbit::new},
- new Supplier[]{Hunter::new},
- new Supplier[]{Rogue::new},
- new Supplier[]{Wizard::new}
+ static Stream dataProvider() {
+ return Stream.of(
+ Arguments.of((Supplier) Hobbit::new),
+ Arguments.of((Supplier) Hunter::new),
+ Arguments.of((Supplier) Rogue::new),
+ Arguments.of((Supplier) Wizard::new)
);
}
@@ -75,9 +75,9 @@ public class PartyMemberTest {
@ParameterizedTest
@MethodSource("dataProvider")
public void testPartyAction(Supplier memberSupplier) {
- final PartyMember member = memberSupplier.get();
+ final var member = memberSupplier.get();
- for (final Action action : Action.values()) {
+ for (final var action : Action.values()) {
member.partyAction(action);
assertEquals(member.toString() + " " + action.getDescription(), appender.getLastMessage());
}
@@ -91,16 +91,16 @@ public class PartyMemberTest {
@ParameterizedTest
@MethodSource("dataProvider")
public void testAct(Supplier memberSupplier) {
- final PartyMember member = memberSupplier.get();
+ final var member = memberSupplier.get();
member.act(Action.GOLD);
assertEquals(0, appender.getLogSize());
- final Party party = mock(Party.class);
+ final var party = mock(Party.class);
member.joinedParty(party);
assertEquals(member.toString() + " joins the party", appender.getLastMessage());
- for (final Action action : Action.values()) {
+ for (final var action : Action.values()) {
member.act(action);
assertEquals(member.toString() + " " + action.toString(), appender.getLastMessage());
verify(party).act(member, action);
@@ -114,16 +114,16 @@ public class PartyMemberTest {
*/
@ParameterizedTest
@MethodSource("dataProvider")
- public void testToString(Supplier memberSupplier) throws Exception {
- final PartyMember member = memberSupplier.get();
- final Class extends PartyMember> memberClass = member.getClass();
+ public void testToString(Supplier memberSupplier) {
+ final var member = memberSupplier.get();
+ final var memberClass = member.getClass();
assertEquals(memberClass.getSimpleName(), member.toString());
}
- private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private static class InMemoryAppender extends AppenderBase {
+ private final List log = new LinkedList<>();
- public InMemoryAppender(Class clazz) {
+ public InMemoryAppender(Class> clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
start();
}
diff --git a/memento/README.md b/memento/README.md
index 1bf6e442b..8bbebd36a 100644
--- a/memento/README.md
+++ b/memento/README.md
@@ -12,8 +12,178 @@ tags:
Token
## Intent
-Without violating encapsulation, capture and externalize an
-object's internal state so that the object can be restored to this state later.
+Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored
+to this state later.
+
+## Explanation
+Real world example
+
+> We are working on astrology application where we need to analyze star properties over time. We are creating snapshots of star state using Memento pattern.
+
+In plain words
+
+> Memento pattern captures object internal state making it easy to store and restore objects in any point of time.
+
+Wikipedia says
+
+> The memento pattern is a software design pattern that provides the ability to restore an object to its previous state (undo via rollback).
+
+**Programmatic Example**
+
+Let's first define the types of stars we are capable to handle.
+
+```java
+public enum StarType {
+ SUN("sun"),
+ RED_GIANT("red giant"),
+ WHITE_DWARF("white dwarf"),
+ SUPERNOVA("supernova"),
+ DEAD("dead star"),
+ UNDEFINED("");
+
+ private final String title;
+
+ StarType(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
+```
+
+Next let's jump straight to the essentials. Here's the star class along with the mementos that we need manipulate.
+
+```java
+public interface StarMemento {
+}
+
+public class Star {
+
+ private StarType type;
+ private int ageYears;
+ private int massTons;
+
+ public Star(StarType startType, int startAge, int startMass) {
+ this.type = startType;
+ this.ageYears = startAge;
+ this.massTons = startMass;
+ }
+
+ public void timePasses() {
+ ageYears *= 2;
+ massTons *= 8;
+ switch (type) {
+ case RED_GIANT:
+ type = StarType.WHITE_DWARF;
+ break;
+ case SUN:
+ type = StarType.RED_GIANT;
+ break;
+ case SUPERNOVA:
+ type = StarType.DEAD;
+ break;
+ case WHITE_DWARF:
+ type = StarType.SUPERNOVA;
+ break;
+ case DEAD:
+ ageYears *= 2;
+ massTons = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ StarMemento getMemento() {
+ var state = new StarMementoInternal();
+ state.setAgeYears(ageYears);
+ state.setMassTons(massTons);
+ state.setType(type);
+ return state;
+ }
+
+ void setMemento(StarMemento memento) {
+ var state = (StarMementoInternal) memento;
+ this.type = state.getType();
+ this.ageYears = state.getAgeYears();
+ this.massTons = state.getMassTons();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s age: %d years mass: %d tons", type.toString(), ageYears, massTons);
+ }
+
+ private static class StarMementoInternal implements StarMemento {
+
+ private StarType type;
+ private int ageYears;
+ private int massTons;
+
+ public StarType getType() {
+ return type;
+ }
+
+ public void setType(StarType type) {
+ this.type = type;
+ }
+
+ public int getAgeYears() {
+ return ageYears;
+ }
+
+ public void setAgeYears(int ageYears) {
+ this.ageYears = ageYears;
+ }
+
+ public int getMassTons() {
+ return massTons;
+ }
+
+ public void setMassTons(int massTons) {
+ this.massTons = massTons;
+ }
+ }
+}
+```
+
+And finally here's how we use the mementos to store and restore star states.
+
+```java
+ var states = new Stack<>();
+ var star = new Star(StarType.SUN, 10000000, 500000);
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ states.add(star.getMemento());
+ star.timePasses();
+ LOGGER.info(star.toString());
+ while (states.size() > 0) {
+ star.setMemento(states.pop());
+ LOGGER.info(star.toString());
+ }
+
+ // sun age: 10000000 years mass: 500000 tons
+ // red giant age: 20000000 years mass: 4000000 tons
+ // white dwarf age: 40000000 years mass: 32000000 tons
+ // supernova age: 80000000 years mass: 256000000 tons
+ // dead star age: 160000000 years mass: 2048000000 tons
+ // supernova age: 80000000 years mass: 256000000 tons
+ // white dwarf age: 40000000 years mass: 32000000 tons
+ // red giant age: 20000000 years mass: 4000000 tons
+ // sun age: 10000000 years mass: 500000 tons
+```
+
## Class diagram

diff --git a/memento/src/main/java/com/iluwatar/memento/App.java b/memento/src/main/java/com/iluwatar/memento/App.java
index af57d8d4a..77cc0f214 100644
--- a/memento/src/main/java/com/iluwatar/memento/App.java
+++ b/memento/src/main/java/com/iluwatar/memento/App.java
@@ -52,9 +52,9 @@ public class App {
* Program entry point.
*/
public static void main(String[] args) {
- Stack states = new Stack<>();
+ var states = new Stack();
- Star star = new Star(StarType.SUN, 10000000, 500000);
+ var star = new Star(StarType.SUN, 10000000, 500000);
LOGGER.info(star.toString());
states.add(star.getMemento());
star.timePasses();
diff --git a/memento/src/main/java/com/iluwatar/memento/Star.java b/memento/src/main/java/com/iluwatar/memento/Star.java
index ebeea28f2..af1c98b04 100644
--- a/memento/src/main/java/com/iluwatar/memento/Star.java
+++ b/memento/src/main/java/com/iluwatar/memento/Star.java
@@ -70,22 +70,18 @@ public class Star {
}
StarMemento getMemento() {
-
- StarMementoInternal state = new StarMementoInternal();
+ var state = new StarMementoInternal();
state.setAgeYears(ageYears);
state.setMassTons(massTons);
state.setType(type);
return state;
-
}
void setMemento(StarMemento memento) {
-
- StarMementoInternal state = (StarMementoInternal) memento;
+ var state = (StarMementoInternal) memento;
this.type = state.getType();
this.ageYears = state.getAgeYears();
this.massTons = state.getMassTons();
-
}
@Override
diff --git a/memento/src/main/java/com/iluwatar/memento/StarType.java b/memento/src/main/java/com/iluwatar/memento/StarType.java
index 507cd506b..aa92bf6e6 100644
--- a/memento/src/main/java/com/iluwatar/memento/StarType.java
+++ b/memento/src/main/java/com/iluwatar/memento/StarType.java
@@ -27,11 +27,14 @@ package com.iluwatar.memento;
* StarType enumeration.
*/
public enum StarType {
+ SUN("sun"),
+ RED_GIANT("red giant"),
+ WHITE_DWARF("white dwarf"),
+ SUPERNOVA("supernova"),
+ DEAD("dead star"),
+ UNDEFINED("");
- SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
- "dead star"), UNDEFINED("");
-
- private String title;
+ private final String title;
StarType(String title) {
this.title = title;
diff --git a/memento/src/test/java/com/iluwatar/memento/AppTest.java b/memento/src/test/java/com/iluwatar/memento/AppTest.java
index 074de2c41..e0448c289 100644
--- a/memento/src/test/java/com/iluwatar/memento/AppTest.java
+++ b/memento/src/test/java/com/iluwatar/memento/AppTest.java
@@ -26,15 +26,12 @@ package com.iluwatar.memento;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/memento/src/test/java/com/iluwatar/memento/StarTest.java b/memento/src/test/java/com/iluwatar/memento/StarTest.java
index 40adb99e1..aab59e9c3 100644
--- a/memento/src/test/java/com/iluwatar/memento/StarTest.java
+++ b/memento/src/test/java/com/iluwatar/memento/StarTest.java
@@ -23,10 +23,10 @@
package com.iluwatar.memento;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
+
/**
* Date: 12/20/15 - 10:08 AM
*
@@ -39,7 +39,7 @@ public class StarTest {
*/
@Test
public void testTimePasses() {
- final Star star = new Star(StarType.SUN, 1, 2);
+ final var star = new Star(StarType.SUN, 1, 2);
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
star.timePasses();
@@ -66,16 +66,16 @@ public class StarTest {
*/
@Test
public void testSetMemento() {
- final Star star = new Star(StarType.SUN, 1, 2);
- final StarMemento firstMemento = star.getMemento();
+ final var star = new Star(StarType.SUN, 1, 2);
+ final var firstMemento = star.getMemento();
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
star.timePasses();
- final StarMemento secondMemento = star.getMemento();
+ final var secondMemento = star.getMemento();
assertEquals("red giant age: 2 years mass: 16 tons", star.toString());
star.timePasses();
- final StarMemento thirdMemento = star.getMemento();
+ final var thirdMemento = star.getMemento();
assertEquals("white dwarf age: 4 years mass: 128 tons", star.toString());
star.timePasses();
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java
index 4607f009d..cabc4d96f 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/App.java
@@ -47,9 +47,9 @@ public class App {
*/
public static void main(String[] args) {
// create model, view and controller
- GiantModel giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
- GiantView view = new GiantView();
- GiantController controller = new GiantController(giant, view);
+ var giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ var view = new GiantView();
+ var controller = new GiantController(giant, view);
// initial display
controller.updateView();
// controller receives some interactions that affect the giant
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java
index b1663df1f..64bae6e51 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Fatigue.java
@@ -27,10 +27,11 @@ package com.iluwatar.model.view.controller;
* Fatigue enumeration.
*/
public enum Fatigue {
+ ALERT("alert"),
+ TIRED("tired"),
+ SLEEPING("sleeping");
- ALERT("alert"), TIRED("tired"), SLEEPING("sleeping");
-
- private String title;
+ private final String title;
Fatigue(String title) {
this.title = title;
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java
index e66608117..f96113574 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/GiantController.java
@@ -28,14 +28,15 @@ package com.iluwatar.model.view.controller;
*/
public class GiantController {
- private GiantModel giant;
- private GiantView view;
+ private final GiantModel giant;
+ private final GiantView view;
public GiantController(GiantModel giant, GiantView view) {
this.giant = giant;
this.view = view;
}
+ @SuppressWarnings("UnusedReturnValue")
public Health getHealth() {
return giant.getHealth();
}
@@ -44,6 +45,7 @@ public class GiantController {
this.giant.setHealth(health);
}
+ @SuppressWarnings("UnusedReturnValue")
public Fatigue getFatigue() {
return giant.getFatigue();
}
@@ -52,6 +54,7 @@ public class GiantController {
this.giant.setFatigue(fatigue);
}
+ @SuppressWarnings("UnusedReturnValue")
public Nourishment getNourishment() {
return giant.getNourishment();
}
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java
index 30b3b2b90..f15585cdd 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Health.java
@@ -27,10 +27,11 @@ package com.iluwatar.model.view.controller;
* Health enumeration.
*/
public enum Health {
+ HEALTHY("healthy"),
+ WOUNDED("wounded"),
+ DEAD("dead");
- HEALTHY("healthy"), WOUNDED("wounded"), DEAD("dead");
-
- private String title;
+ private final String title;
Health(String title) {
this.title = title;
diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java
index 3ced564cc..ba00c38c5 100644
--- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java
+++ b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/Nourishment.java
@@ -27,10 +27,11 @@ package com.iluwatar.model.view.controller;
* Nourishment enumeration.
*/
public enum Nourishment {
+ SATURATED("saturated"),
+ HUNGRY("hungry"),
+ STARVING("starving");
- SATURATED("saturated"), HUNGRY("hungry"), STARVING("starving");
-
- private String title;
+ private final String title;
Nourishment(String title) {
this.title = title;
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
index e6d2d9a0b..69dc19f1c 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
@@ -26,15 +26,12 @@ package com.iluwatar.model.view.controller;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
index a2f42a80d..d106d0944 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
@@ -23,13 +23,13 @@
package com.iluwatar.model.view.controller;
-import org.junit.jupiter.api.Test;
-
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 org.junit.jupiter.api.Test;
+
/**
* Date: 12/20/15 - 2:19 PM
*
@@ -42,19 +42,20 @@ public class GiantControllerTest {
*/
@Test
public void testSetHealth() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
- for (final Health health : Health.values()) {
+ for (final var health : Health.values()) {
controller.setHealth(health);
verify(model).setHealth(health);
verifyZeroInteractions(view);
}
controller.getHealth();
+ //noinspection ResultOfMethodCallIgnored
verify(model).getHealth();
verifyNoMoreInteractions(model, view);
@@ -65,19 +66,20 @@ public class GiantControllerTest {
*/
@Test
public void testSetFatigue() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
- for (final Fatigue fatigue : Fatigue.values()) {
+ for (final var fatigue : Fatigue.values()) {
controller.setFatigue(fatigue);
verify(model).setFatigue(fatigue);
verifyZeroInteractions(view);
}
controller.getFatigue();
+ //noinspection ResultOfMethodCallIgnored
verify(model).getFatigue();
verifyNoMoreInteractions(model, view);
@@ -88,19 +90,20 @@ public class GiantControllerTest {
*/
@Test
public void testSetNourishment() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
- for (final Nourishment nourishment : Nourishment.values()) {
+ for (final var nourishment : Nourishment.values()) {
controller.setNourishment(nourishment);
verify(model).setNourishment(nourishment);
verifyZeroInteractions(view);
}
controller.getNourishment();
+ //noinspection ResultOfMethodCallIgnored
verify(model).getNourishment();
verifyNoMoreInteractions(model, view);
@@ -108,9 +111,9 @@ public class GiantControllerTest {
@Test
public void testUpdateView() {
- final GiantModel model = mock(GiantModel.class);
- final GiantView view = mock(GiantView.class);
- final GiantController controller = new GiantController(model, view);
+ final var model = mock(GiantModel.class);
+ final var view = mock(GiantView.class);
+ final var controller = new GiantController(model, view);
verifyZeroInteractions(model, view);
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
index a566010cd..677ab436e 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
@@ -23,10 +23,10 @@
package com.iluwatar.model.view.controller;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
+
/**
* Date: 12/20/15 - 2:10 PM
*
@@ -39,12 +39,13 @@ public class GiantModelTest {
*/
@Test
public void testSetHealth() {
- final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
assertEquals(Health.HEALTHY, model.getHealth());
- for (final Health health : Health.values()) {
+ var messageFormat = "The giant looks %s, alert and saturated.";
+ for (final var health : Health.values()) {
model.setHealth(health);
assertEquals(health, model.getHealth());
- assertEquals("The giant looks " + health.toString() + ", alert and saturated.", model.toString());
+ assertEquals(String.format(messageFormat, health), model.toString());
}
}
@@ -53,12 +54,13 @@ public class GiantModelTest {
*/
@Test
public void testSetFatigue() {
- final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
assertEquals(Fatigue.ALERT, model.getFatigue());
- for (final Fatigue fatigue : Fatigue.values()) {
+ var messageFormat = "The giant looks healthy, %s and saturated.";
+ for (final var fatigue : Fatigue.values()) {
model.setFatigue(fatigue);
assertEquals(fatigue, model.getFatigue());
- assertEquals("The giant looks healthy, " + fatigue.toString() + " and saturated.", model.toString());
+ assertEquals(String.format(messageFormat, fatigue), model.toString());
}
}
@@ -67,12 +69,13 @@ public class GiantModelTest {
*/
@Test
public void testSetNourishment() {
- final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
assertEquals(Nourishment.SATURATED, model.getNourishment());
- for (final Nourishment nourishment : Nourishment.values()) {
+ var messageFormat = "The giant looks healthy, alert and %s.";
+ for (final var nourishment : Nourishment.values()) {
model.setNourishment(nourishment);
assertEquals(nourishment, model.getNourishment());
- assertEquals("The giant looks healthy, alert and " + nourishment.toString() + ".", model.toString());
+ assertEquals(String.format(messageFormat, nourishment), model.toString());
}
}
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 a3e33f9dd..c6314c1dd 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
@@ -31,7 +31,6 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.util.LinkedList;
import java.util.List;
-
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -62,9 +61,9 @@ public class GiantViewTest {
*/
@Test
public void testDisplayGiant() {
- final GiantView view = new GiantView();
+ final var view = new GiantView();
- final GiantModel model = mock(GiantModel.class);
+ final var model = mock(GiantModel.class);
view.displayGiant(model);
assertEquals(model.toString(), appender.getLastMessage());
@@ -74,10 +73,10 @@ public class GiantViewTest {
/**
* Logging Appender Implementation
*/
- public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ public static class InMemoryAppender extends AppenderBase {
+ private final List log = new LinkedList<>();
- public InMemoryAppender(Class clazz) {
+ public InMemoryAppender(Class> clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
start();
}
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java
index 43984e847..ac3b83927 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/App.java
@@ -44,9 +44,9 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- FileLoader loader = new FileLoader();
- FileSelectorJFrame frame = new FileSelectorJFrame();
- FileSelectorPresenter presenter = new FileSelectorPresenter(frame);
+ var loader = new FileLoader();
+ var frame = new FileSelectorJFrame();
+ var presenter = new FileSelectorPresenter(frame);
presenter.setLoader(loader);
presenter.start();
}
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 9c01b2044..7dd5dd215 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
@@ -27,6 +27,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Serializable;
+import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,18 +60,11 @@ public class FileLoader implements Serializable {
* Loads the data of the file specified.
*/
public String loadData() {
- String dataFileName = this.fileName;
- try (BufferedReader br = new BufferedReader(new FileReader(new File(dataFileName)))) {
- StringBuilder sb = new StringBuilder();
- String line;
-
- while ((line = br.readLine()) != null) {
- sb.append(line).append('\n');
- }
-
+ var dataFileName = this.fileName;
+ try (var br = new BufferedReader(new FileReader(new File(dataFileName)))) {
+ var result = br.lines().collect(Collectors.joining("\n"));
this.loaded = true;
-
- return sb.toString();
+ return result;
} catch (Exception e) {
LOGGER.error("File {} does not exist", dataFileName);
}
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
index 77523ccaa..1d59b5d8c 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
@@ -48,37 +48,22 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/**
* The "OK" button for loading the file.
*/
- private JButton ok;
+ private final JButton ok;
/**
* The cancel button.
*/
- private JButton cancel;
-
- /**
- * The information label.
- */
- private JLabel info;
-
- /**
- * The contents label.
- */
- private JLabel contents;
+ private final JButton cancel;
/**
* The text field for giving the name of the file that we want to open.
*/
- private JTextField input;
+ private final JTextField input;
/**
* A text area that will keep the contents of the file opened.
*/
- private JTextArea area;
-
- /**
- * The panel that will hold our widgets.
- */
- private JPanel panel;
+ private final JTextArea area;
/**
* The Presenter component that the frame will interact with.
@@ -102,7 +87,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/*
* Add the panel.
*/
- this.panel = new JPanel();
+ var panel = new JPanel();
panel.setLayout(null);
this.add(panel);
panel.setBounds(0, 0, 500, 200);
@@ -111,32 +96,32 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/*
* Add the info label.
*/
- this.info = new JLabel("File Name :");
- this.panel.add(info);
+ var info = new JLabel("File Name :");
+ panel.add(info);
info.setBounds(30, 10, 100, 30);
/*
* Add the contents label.
*/
- this.contents = new JLabel("File contents :");
- this.panel.add(contents);
- this.contents.setBounds(30, 100, 120, 30);
+ var contents = new JLabel("File contents :");
+ panel.add(contents);
+ contents.setBounds(30, 100, 120, 30);
/*
* Add the text field.
*/
this.input = new JTextField(100);
- this.panel.add(input);
+ panel.add(input);
this.input.setBounds(150, 15, 200, 20);
/*
* Add the text area.
*/
this.area = new JTextArea(100, 100);
- JScrollPane pane = new JScrollPane(area);
+ var pane = new JScrollPane(area);
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
- this.panel.add(pane);
+ panel.add(pane);
this.area.setEditable(false);
pane.setBounds(150, 100, 250, 80);
@@ -144,7 +129,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
* Add the OK button.
*/
this.ok = new JButton("OK");
- this.panel.add(ok);
+ panel.add(ok);
this.ok.setBounds(250, 50, 100, 25);
this.ok.addActionListener(this);
@@ -152,7 +137,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
* Add the cancel button.
*/
this.cancel = new JButton("Cancel");
- this.panel.add(this.cancel);
+ panel.add(this.cancel);
this.cancel.setBounds(380, 50, 100, 25);
this.cancel.addActionListener(this);
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 35e1c0076..5cd6580d9 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
@@ -41,7 +41,7 @@ public class FileSelectorPresenter implements Serializable {
/**
* The View component that the presenter interacts with.
*/
- private FileSelectorView view;
+ private final FileSelectorView view;
/**
* The Model component that the presenter interacts with.
@@ -91,7 +91,7 @@ public class FileSelectorPresenter implements Serializable {
}
if (loader.fileExists()) {
- String data = loader.loadData();
+ var data = loader.loadData();
view.displayData(data);
} else {
view.showMessage("The file specified does not exist.");
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
index 00e35ae1b..4db990a2d 100644
--- a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
@@ -26,16 +26,13 @@ package com.iluwatar.model.view.presenter;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
index a63ca5ae8..3787cd20b 100644
--- a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
@@ -23,10 +23,10 @@
package com.iluwatar.model.view.presenter;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertNull;
+import org.junit.jupiter.api.Test;
+
/**
* Date: 12/21/15 - 12:12 PM
*
@@ -35,8 +35,8 @@ import static org.junit.jupiter.api.Assertions.assertNull;
public class FileLoaderTest {
@Test
- public void testLoadData() throws Exception {
- final FileLoader fileLoader = new FileLoader();
+ public void testLoadData() {
+ final var fileLoader = new FileLoader();
fileLoader.setFileName("non-existing-file");
assertNull(fileLoader.loadData());
}
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
index fdc19398d..238d3a135 100644
--- a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
@@ -23,14 +23,14 @@
package com.iluwatar.model.view.presenter;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
/**
* This test case is responsible for testing our application by taking advantage of the
* Model-View-Controller architectural pattern.
@@ -79,7 +79,7 @@ public class FileSelectorPresenterTest {
*/
@Test
public void updateFileNameToLoader() {
- String expectedFile = "Stamatis";
+ var expectedFile = "Stamatis";
stub.setFileName(expectedFile);
presenter.start();
diff --git a/module/pom.xml b/module/pom.xml
index 25ad707eb..5d9a6d529 100644
--- a/module/pom.xml
+++ b/module/pom.xml
@@ -23,38 +23,39 @@
THE SOFTWARE.
-->
-
- 4.0.0
-
- com.iluwatar
- java-design-patterns
- 1.23.0-SNAPSHOT
-
- module
-
-
- org.junit.jupiter
- junit-jupiter-engine
- test
-
-
-
-
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
-
-
-
- com.iluwatar.module.App
-
-
-
-
-
-
-
-
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.23.0-SNAPSHOT
+
+ module
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.module.App
+
+
+
+
+
+
+
+
diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java
index d50693440..0f89d8f89 100644
--- a/module/src/main/java/com/iluwatar/module/App.java
+++ b/module/src/main/java/com/iluwatar/module/App.java
@@ -67,10 +67,8 @@ public class App {
/**
* Following method is main executor.
- *
- * @param args for providing default program arguments
*/
- public static void execute(final String... args) {
+ public static void execute() {
/* Send logs on file system */
fileLoggerModule.printString(MESSAGE);
@@ -90,7 +88,7 @@ public class App {
*/
public static void main(final String... args) throws FileNotFoundException {
prepare();
- execute(args);
+ execute();
unprepare();
}
}
diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java
index 88fa4c68c..8dcfd565e 100644
--- a/module/src/test/java/com/iluwatar/module/AppTest.java
+++ b/module/src/test/java/com/iluwatar/module/AppTest.java
@@ -23,9 +23,8 @@
package com.iluwatar.module;
-import org.junit.jupiter.api.Test;
-
import java.io.FileNotFoundException;
+import org.junit.jupiter.api.Test;
/**
* Tests that Module example runs without errors.
@@ -34,7 +33,6 @@ public final class AppTest {
@Test
public void test() throws FileNotFoundException {
- final String[] args = {};
- App.main(args);
+ App.main();
}
}
diff --git a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java
index 646bba642..6497aa89d 100644
--- a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java
+++ b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java
@@ -23,17 +23,16 @@
package com.iluwatar.module;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* The Module pattern can be considered a Creational pattern and a Structural pattern. It manages
@@ -58,7 +57,7 @@ public final class FileLoggerModuleTest {
/**
* 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
@@ -82,13 +81,13 @@ public final class FileLoggerModuleTest {
/**
* 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 testNoFileMessage() throws IOException {
- /* Get singletong instance of File Logger Module */
+ /* Get singleton instance of File Logger Module */
final var fileLoggerModule = FileLoggerModule.getSingleton();
/* Prepare the essential sub modules, to perform the sequence of jobs */
@@ -103,9 +102,9 @@ public final class FileLoggerModuleTest {
/**
* 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)
+ * error.txt)
*/
@Test
public void testFileErrorMessage() throws FileNotFoundException {
@@ -122,15 +121,15 @@ public final class FileLoggerModuleTest {
/* Test if 'Message' is printed in file */
assertEquals(ERROR, readFirstLine(ERROR_FILE));
- /* Unprepare to cleanup the modules */
+ /* Un-prepare to cleanup the modules */
fileLoggerModule.unprepare();
}
/**
* This test verify that nothing is printed in error file
- *
+ *
* @throws FileNotFoundException if program is not able to find log files (output.txt and
- * error.txt)
+ * error.txt)
*/
@Test
public void testNoFileErrorMessage() throws FileNotFoundException {
@@ -150,11 +149,11 @@ public final class FileLoggerModuleTest {
/**
* 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) {
+ private static String readFirstLine(final String file) {
String firstLine = null;
try (var bufferedReader = new BufferedReader(new FileReader(file))) {
diff --git a/monad/src/main/java/com/iluwatar/monad/App.java b/monad/src/main/java/com/iluwatar/monad/App.java
index ccb42edd0..bb3315064 100644
--- a/monad/src/main/java/com/iluwatar/monad/App.java
+++ b/monad/src/main/java/com/iluwatar/monad/App.java
@@ -41,9 +41,8 @@ import org.slf4j.LoggerFactory;
* instance of a plain object with {@link Validator#of(Object)} and validates it {@link
* Validator#validate(Function, Predicate, String)} against given predicates.
*
- * As a validation result {@link Validator#get()} it either returns valid object {@link
- * Validator#t} or throws a list of exceptions {@link Validator#exceptions} collected during
- * validation.
+ *
As a validation result {@link Validator#get()} either returns valid object
+ * or throws {@link IllegalStateException} with list of exceptions collected during validation.
*/
public class App {
@@ -55,10 +54,10 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- User user = new User("user", 24, Sex.FEMALE, "foobar.com");
+ var user = new User("user", 24, Sex.FEMALE, "foobar.com");
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::getEmail, email -> !email.contains("@"), "email doesn't contains '@'")
.validate(User::getAge, age -> age > 20 && age < 30, "age isn't between...").get()
.toString());
}
diff --git a/monad/src/main/java/com/iluwatar/monad/User.java b/monad/src/main/java/com/iluwatar/monad/User.java
index 77766d1aa..8644c4c0a 100644
--- a/monad/src/main/java/com/iluwatar/monad/User.java
+++ b/monad/src/main/java/com/iluwatar/monad/User.java
@@ -1,66 +1,66 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.monad;
-
-/**
- * User Definition.
- */
-public class User {
-
- private String name;
- private int age;
- private Sex sex;
- private String email;
-
- /**
- * Constructor.
- *
- * @param name - name
- * @param age - age
- * @param sex - sex
- * @param email - email address
- */
- public User(String name, int age, Sex sex, String email) {
- this.name = name;
- this.age = age;
- this.sex = sex;
- this.email = email;
- }
-
- public String getName() {
- return name;
- }
-
- public int getAge() {
- return age;
- }
-
- public Sex getSex() {
- return sex;
- }
-
- public String getEmail() {
- return email;
- }
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.monad;
+
+/**
+ * User Definition.
+ */
+public class User {
+
+ private final String name;
+ private final int age;
+ private final Sex sex;
+ private final String email;
+
+ /**
+ * Constructor.
+ *
+ * @param name - name
+ * @param age - age
+ * @param sex - sex
+ * @param email - email address
+ */
+ public User(String name, int age, Sex sex, String email) {
+ this.name = name;
+ this.age = age;
+ this.sex = sex;
+ this.email = email;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public Sex getSex() {
+ return sex;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+}
diff --git a/monad/src/main/java/com/iluwatar/monad/Validator.java b/monad/src/main/java/com/iluwatar/monad/Validator.java
index 2d1f1bdab..47acc8a42 100644
--- a/monad/src/main/java/com/iluwatar/monad/Validator.java
+++ b/monad/src/main/java/com/iluwatar/monad/Validator.java
@@ -85,18 +85,21 @@ public class Validator {
}
/**
- * Extension for the {@link Validator#validate(Function, Predicate, String)} method, dedicated for
- * objects, that need to be projected before requested validation.
+ * Extension for the {@link Validator#validate(Predicate, String)} method, dedicated for objects,
+ * that need to be projected before requested validation.
*
* @param projection function that gets an objects, and returns projection representing element to
* be validated.
- * @param validation see {@link Validator#validate(Function, Predicate, String)}
- * @param message see {@link Validator#validate(Function, Predicate, String)}
- * @param see {@link Validator#validate(Function, Predicate, String)}
+ * @param validation see {@link Validator#validate(Predicate, String)}
+ * @param message see {@link Validator#validate(Predicate, String)}
+ * @param see {@link Validator#validate(Predicate, String)}
* @return this
*/
- public Validator validate(Function projection, Predicate validation,
- String message) {
+ public Validator validate(
+ Function projection,
+ Predicate validation,
+ String message
+ ) {
return validate(projection.andThen(validation::test)::apply, message);
}
@@ -110,7 +113,7 @@ public class Validator {
if (exceptions.isEmpty()) {
return obj;
}
- IllegalStateException e = new IllegalStateException();
+ var e = new IllegalStateException();
exceptions.forEach(e::addSuppressed);
throw e;
}
diff --git a/monad/src/test/java/com/iluwatar/monad/AppTest.java b/monad/src/test/java/com/iluwatar/monad/AppTest.java
index f4d89a7cd..d56270173 100644
--- a/monad/src/test/java/com/iluwatar/monad/AppTest.java
+++ b/monad/src/test/java/com/iluwatar/monad/AppTest.java
@@ -32,8 +32,7 @@ public class AppTest {
@Test
public void testMain() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/monad/src/test/java/com/iluwatar/monad/MonadTest.java b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
index d1bdd7487..afd5b50f8 100644
--- a/monad/src/test/java/com/iluwatar/monad/MonadTest.java
+++ b/monad/src/test/java/com/iluwatar/monad/MonadTest.java
@@ -23,13 +23,12 @@
package com.iluwatar.monad;
-import org.junit.jupiter.api.Test;
-
-import java.util.Objects;
-
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.util.Objects;
+import org.junit.jupiter.api.Test;
+
/**
* Test for Monad Pattern
*/
@@ -37,27 +36,33 @@ public class MonadTest {
@Test
public void testForInvalidName() {
- User tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
- assertThrows(IllegalStateException.class, () -> {
- Validator.of(tom).validate(User::getName, Objects::nonNull, "name cannot be null").get();
- });
+ var tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
+ assertThrows(
+ IllegalStateException.class,
+ () -> Validator.of(tom)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .get()
+ );
}
@Test
public void testForInvalidAge() {
- User john = new User("John", 17, Sex.MALE, "john@qwe.bar");
- assertThrows(IllegalStateException.class, () -> {
- Validator.of(john).validate(User::getName, Objects::nonNull, "name cannot be null")
- .validate(User::getAge, age -> age > 21, "user is underaged")
- .get();
- });
+ var john = new User("John", 17, Sex.MALE, "john@qwe.bar");
+ assertThrows(
+ IllegalStateException.class,
+ () -> Validator.of(john)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underage")
+ .get()
+ );
}
@Test
public void testForValid() {
- User sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
- User validated = Validator.of(sarah).validate(User::getName, Objects::nonNull, "name cannot be null")
- .validate(User::getAge, age -> age > 21, "user is underaged")
+ var sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
+ var validated = Validator.of(sarah)
+ .validate(User::getName, Objects::nonNull, "name cannot be null")
+ .validate(User::getAge, age -> age > 21, "user is underage")
.validate(User::getSex, sex -> sex == Sex.FEMALE, "user is not female")
.validate(User::getEmail, email -> email.contains("@"), "email does not contain @ sign")
.get();
diff --git a/monostate/src/main/java/com/iluwatar/monostate/App.java b/monostate/src/main/java/com/iluwatar/monostate/App.java
index 64cb38461..9f5b2c173 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/App.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/App.java
@@ -30,7 +30,7 @@ package com.iluwatar.monostate;
*
* In the following example, The {@link LoadBalancer} class represents the app's logic. It
* contains a series of Servers, which can handle requests of type {@link Request}. Two instances of
- * LoadBalacer are created. When a request is made to a server via the first LoadBalancer the state
+ * LoadBalancer are created. When a request is made to a server via the first LoadBalancer the state
* change in the first load balancer affects the second. So if the first LoadBalancer selects the
* Server 1, the second LoadBalancer on a new request will select the Second server. If a third
* LoadBalancer is created and a new request is made to it, then it will select the third server as
@@ -43,8 +43,8 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- LoadBalancer loadBalancer1 = new LoadBalancer();
- LoadBalancer loadBalancer2 = new LoadBalancer();
+ var loadBalancer1 = new LoadBalancer();
+ var loadBalancer2 = new LoadBalancer();
loadBalancer1.serverRequest(new Request("Hello"));
loadBalancer2.serverRequest(new Request("Hello World"));
}
diff --git a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
index 8546ae177..7a784f514 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
@@ -38,8 +38,8 @@ public class LoadBalancer {
private static int lastServedId;
static {
- int id = 0;
- for (int port : new int[]{8080, 8081, 8082, 8083, 8084}) {
+ var id = 0;
+ for (var port : new int[]{8080, 8081, 8082, 8083, 8084}) {
SERVERS.add(new Server("localhost", port, ++id));
}
}
@@ -69,7 +69,7 @@ public class LoadBalancer {
if (lastServedId >= SERVERS.size()) {
lastServedId = 0;
}
- Server server = SERVERS.get(lastServedId++);
+ var server = SERVERS.get(lastServedId++);
server.serve(request);
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
index c914f136e..d17a56bb9 100644
--- a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
+++ b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
@@ -32,8 +32,7 @@ public class AppTest {
@Test
public void testMain() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
index 736bf6ea6..d62c029e2 100644
--- a/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
+++ b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
@@ -44,8 +44,8 @@ public class LoadBalancerTest {
@Test
public void testSameStateAmongstAllInstances() {
- final LoadBalancer firstBalancer = new LoadBalancer();
- final LoadBalancer secondBalancer = new LoadBalancer();
+ final var firstBalancer = new LoadBalancer();
+ final var secondBalancer = new LoadBalancer();
firstBalancer.addServer(new Server("localhost", 8085, 6));
// Both should have the same number of servers.
assertEquals(firstBalancer.getNoOfServers(), secondBalancer.getNoOfServers());
@@ -55,18 +55,18 @@ public class LoadBalancerTest {
@Test
public void testServe() {
- final Server server = mock(Server.class);
+ final var server = mock(Server.class);
when(server.getHost()).thenReturn("testhost");
when(server.getPort()).thenReturn(1234);
doNothing().when(server).serve(any(Request.class));
- final LoadBalancer loadBalancer = new LoadBalancer();
+ final var loadBalancer = new LoadBalancer();
loadBalancer.addServer(server);
verifyZeroInteractions(server);
- final Request request = new Request("test");
- for (int i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
+ final var request = new Request("test");
+ for (var i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
loadBalancer.serverRequest(request);
}
diff --git a/multiton/README.md b/multiton/README.md
index 4387cf7ac..85ce3acf2 100644
--- a/multiton/README.md
+++ b/multiton/README.md
@@ -12,8 +12,88 @@ tags:
Registry
## Intent
-Ensure a class only has limited number of instances, and provide a
-global point of access to them.
+Ensure a class only has limited number of instances and provide a global point of access to them.
+
+## Explanation
+
+Real world example
+
+> The Nazgûl, also called ringwraiths or the Nine Riders, are Sauron's most terrible servants. By definition there's always nine of them.
+
+In plain words
+
+> Multiton pattern ensures there's predefined amount of instances available globally.
+
+Wikipedia says
+
+> In software engineering, the multiton pattern is a design pattern which generalizes the singleton pattern. Whereas the singleton allows only one instance of a class to be created, the multiton pattern allows for the controlled creation of multiple instances, which it manages through the use of a map.
+
+**Programmatic Example**
+
+Nazgul is the multiton class.
+
+```java
+public enum NazgulName {
+
+ KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
+}
+
+public final class Nazgul {
+
+ private static final Map nazguls;
+
+ private final NazgulName name;
+
+ static {
+ nazguls = new ConcurrentHashMap<>();
+ nazguls.put(NazgulName.KHAMUL, new Nazgul(NazgulName.KHAMUL));
+ nazguls.put(NazgulName.MURAZOR, new Nazgul(NazgulName.MURAZOR));
+ nazguls.put(NazgulName.DWAR, new Nazgul(NazgulName.DWAR));
+ nazguls.put(NazgulName.JI_INDUR, new Nazgul(NazgulName.JI_INDUR));
+ nazguls.put(NazgulName.AKHORAHIL, new Nazgul(NazgulName.AKHORAHIL));
+ nazguls.put(NazgulName.HOARMURATH, new Nazgul(NazgulName.HOARMURATH));
+ nazguls.put(NazgulName.ADUNAPHEL, new Nazgul(NazgulName.ADUNAPHEL));
+ nazguls.put(NazgulName.REN, new Nazgul(NazgulName.REN));
+ nazguls.put(NazgulName.UVATHA, new Nazgul(NazgulName.UVATHA));
+ }
+
+ private Nazgul(NazgulName name) {
+ this.name = name;
+ }
+
+ public static Nazgul getInstance(NazgulName name) {
+ return nazguls.get(name);
+ }
+
+ public NazgulName getName() {
+ return name;
+ }
+}
+```
+
+And here's how we access the Nazgul instances.
+
+```java
+ 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));
+
+ // KHAMUL=com.iluwatar.multiton.Nazgul@2b214b94
+ // MURAZOR=com.iluwatar.multiton.Nazgul@17814b1c
+ // DWAR=com.iluwatar.multiton.Nazgul@7ac9af2a
+ // JI_INDUR=com.iluwatar.multiton.Nazgul@7bb004b8
+ // AKHORAHIL=com.iluwatar.multiton.Nazgul@78e89bfe
+ // HOARMURATH=com.iluwatar.multiton.Nazgul@652ce654
+ // ADUNAPHEL=com.iluwatar.multiton.Nazgul@522ba524
+ // REN=com.iluwatar.multiton.Nazgul@29c5ee1d
+ // UVATHA=com.iluwatar.multiton.Nazgul@15cea7b0
+```
## Class diagram

diff --git a/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java b/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
index f55f85aca..e08107eeb 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/Nazgul.java
@@ -31,9 +31,9 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public final class Nazgul {
- private static Map nazguls;
+ private static final Map nazguls;
- private NazgulName name;
+ private final NazgulName name;
static {
nazguls = new ConcurrentHashMap<>();
diff --git a/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java b/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
index 5b5c48d66..bb1454b9f 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/NazgulEnum.java
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
* enum based multiton implementation.
*/
public enum NazgulEnum {
-
- KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA;
-
+ KHAMUL,
+ MURAZOR,
+ DWAR,
+ JI_INDUR,
+ AKHORAHIL,
+ HOARMURATH,
+ ADUNAPHEL,
+ REN,
+ UVATHA
}
diff --git a/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java b/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
index c7865dceb..cce19c6ff 100644
--- a/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
+++ b/multiton/src/main/java/com/iluwatar/multiton/NazgulName.java
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
* Each Nazgul has different {@link NazgulName}.
*/
public enum NazgulName {
-
- KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA;
-
+ KHAMUL,
+ MURAZOR,
+ DWAR,
+ JI_INDUR,
+ AKHORAHIL,
+ HOARMURATH,
+ ADUNAPHEL,
+ REN,
+ UVATHA
}
diff --git a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
index f577b7f07..0496ebdaf 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
@@ -26,15 +26,12 @@ package com.iluwatar.multiton;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
diff --git a/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java b/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
index 6668874f4..4d107a181 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/NazgulEnumTest.java
@@ -39,10 +39,10 @@ class NazgulEnumTest {
*/
@Test
public void testTheSameObjectIsReturnedWithMultipleCalls() {
- for (int i = 0; i < NazgulEnum.values().length; i++) {
- NazgulEnum instance1 = NazgulEnum.values()[i];
- NazgulEnum instance2 = NazgulEnum.values()[i];
- NazgulEnum instance3 = NazgulEnum.values()[i];
+ for (var i = 0; i < NazgulEnum.values().length; i++) {
+ var instance1 = NazgulEnum.values()[i];
+ var instance2 = NazgulEnum.values()[i];
+ var instance3 = NazgulEnum.values()[i];
assertSame(instance1, instance2);
assertSame(instance1, instance3);
assertSame(instance2, instance3);
diff --git a/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
index 0429f8e29..f900659a8 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
@@ -41,8 +41,8 @@ public class NazgulTest {
*/
@Test
public void testGetInstance() {
- for (final NazgulName name : NazgulName.values()) {
- final Nazgul nazgul = Nazgul.getInstance(name);
+ for (final var name : NazgulName.values()) {
+ final var nazgul = Nazgul.getInstance(name);
assertNotNull(nazgul);
assertSame(nazgul, Nazgul.getInstance(name));
assertEquals(name, nazgul.getName());
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 d4f140bf0..eca345014 100644
--- a/mute-idiom/src/main/java/com/iluwatar/mute/App.java
+++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java
@@ -25,7 +25,7 @@ package com.iluwatar.mute;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.sql.SQLException;
+import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,9 +52,8 @@ public class App {
* Program entry point.
*
* @param args command line args.
- * @throws Exception if any exception occurs
*/
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
useOfLoggedMute();
@@ -68,17 +67,17 @@ public class App {
* exception occurs.
*/
private static void useOfMute() {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
+ var out = new ByteArrayOutputStream();
Mute.mute(() -> out.write("Hello".getBytes()));
}
- private static void useOfLoggedMute() throws SQLException {
- Resource resource = null;
+ private static void useOfLoggedMute() {
+ Optional resource = Optional.empty();
try {
- resource = acquireResource();
- utilizeResource(resource);
+ resource = Optional.of(acquireResource());
+ utilizeResource(resource.get());
} finally {
- closeResource(resource);
+ resource.ifPresent(App::closeResource);
}
}
@@ -86,14 +85,14 @@ public class App {
* All we can do while failed close of a resource is to log it.
*/
private static void closeResource(Resource resource) {
- Mute.loggedMute(() -> resource.close());
+ Mute.loggedMute(resource::close);
}
- private static void utilizeResource(Resource resource) throws SQLException {
+ private static void utilizeResource(Resource resource) {
LOGGER.info("Utilizing acquired resource: {}", resource);
}
- private static Resource acquireResource() throws SQLException {
+ private static Resource acquireResource() {
return new Resource() {
@Override
diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
index 5ca525a9d..5883812c7 100644
--- a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
+++ b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java
@@ -27,12 +27,11 @@ import org.junit.jupiter.api.Test;
/**
* Tests that Mute idiom example runs without errors.
- *
*/
public class AppTest {
@Test
- public void test() throws Exception {
- App.main(null);
+ public void test() {
+ App.main(new String[]{});
}
}
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 f2743113b..33d104ffc 100644
--- a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
+++ b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java
@@ -23,17 +23,15 @@
package com.iluwatar.mute;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
/**
* Test for the mute-idiom pattern
*/
@@ -50,9 +48,7 @@ public class MuteTest {
@Test
public void muteShouldRethrowUnexpectedExceptionAsAssertionError() {
- assertThrows(AssertionError.class, () -> {
- Mute.mute(this::methodThrowingException);
- });
+ assertThrows(AssertionError.class, () -> Mute.mute(this::methodThrowingException));
}
@Test
@@ -62,7 +58,7 @@ public class MuteTest {
@Test
public void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ var stream = new ByteArrayOutputStream();
System.setErr(new PrintStream(stream));
Mute.loggedMute(this::methodThrowingException);
diff --git a/mutex/src/main/java/com/iluwatar/mutex/App.java b/mutex/src/main/java/com/iluwatar/mutex/App.java
index e4a952ef9..c50acc65a 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/App.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/App.java
@@ -38,10 +38,10 @@ public class App {
* main method.
*/
public static void main(String[] args) {
- Mutex mutex = new Mutex();
- Jar jar = new Jar(1000, mutex);
- Thief peter = new Thief("Peter", jar);
- Thief john = new Thief("John", jar);
+ var mutex = new Mutex();
+ var jar = new Jar(1000, mutex);
+ var peter = new Thief("Peter", jar);
+ var john = new Thief("John", jar);
peter.start();
john.start();
}
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Jar.java b/mutex/src/main/java/com/iluwatar/mutex/Jar.java
index f68b266ad..4a0861e1a 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/Jar.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/Jar.java
@@ -48,7 +48,7 @@ public class Jar {
* Method for a thief to take a bean.
*/
public boolean takeBean() {
- boolean success = false;
+ var success = false;
try {
lock.acquire();
success = beans > 0;
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Thief.java b/mutex/src/main/java/com/iluwatar/mutex/Thief.java
index 29caba540..a9a715970 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/Thief.java
+++ b/mutex/src/main/java/com/iluwatar/mutex/Thief.java
@@ -54,7 +54,7 @@ public class Thief extends Thread {
*/
@Override
public void run() {
- int beans = 0;
+ var beans = 0;
while (jar.takeBean()) {
beans = beans + 1;
diff --git a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
index 1793bf90b..0bee249a6 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
@@ -25,15 +25,12 @@ package com.iluwatar.mutex;
import org.junit.jupiter.api.Test;
-import java.io.IOException;
-
/**
* Application Test Entrypoint
*/
public class AppTest {
@Test
- public void test() throws IOException {
- String[] args = {};
- App.main(args);
+ public void test() {
+ App.main(new String[]{});
}
}
diff --git a/mutex/src/test/java/com/iluwatar/mutex/JarTest.java b/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
index e0a316072..786f96e44 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/JarTest.java
@@ -23,10 +23,11 @@
package com.iluwatar.mutex;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
/**
* Test case for taking beans from a Jar
@@ -35,12 +36,10 @@ public class JarTest {
@Test
public void testTakeBeans() {
- Mutex mutex = new Mutex();
- Jar jar = new Jar(10, mutex);
- for (int i = 0; i < 10; i++) {
- assertTrue(jar.takeBean());
- }
+ var mutex = new Mutex();
+ var jar = new Jar(10, mutex);
+ IntStream.range(0, 10).mapToObj(i -> jar.takeBean()).forEach(Assertions::assertTrue);
assertFalse(jar.takeBean());
}
-}
\ No newline at end of file
+}
diff --git a/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java b/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
index 2e3184c51..d6d0cc1d7 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/MutexTest.java
@@ -23,12 +23,12 @@
package com.iluwatar.mutex;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
+import org.junit.jupiter.api.Test;
+
/**
* Test case for acquiring and releasing a Mutex
*/
@@ -36,7 +36,7 @@ public class MutexTest {
@Test
public void acquireReleaseTest() {
- Mutex mutex = new Mutex();
+ var mutex = new Mutex();
assertNull(mutex.getOwner());
try {
mutex.acquire();
diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml
index dffc1650c..0437c2da5 100644
--- a/naked-objects/dom/pom.xml
+++ b/naked-objects/dom/pom.xml
@@ -127,7 +127,7 @@
-
+
diff --git a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json
index 638473eee..fe39b5b42 100644
--- a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json
+++ b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageViewModel.layout.json
@@ -1,19 +1,3 @@
-/**
- * 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.
- */
{
"columns": [
{
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 809da6d31..43d96f280 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
@@ -50,9 +50,9 @@ import org.apache.isis.applib.util.ObjectContracts;
strategy = javax.jdo.annotations.IdGeneratorStrategy.IDENTITY, column = "id")
@javax.jdo.annotations.Version(strategy = VersionStrategy.VERSION_NUMBER, column = "version")
@javax.jdo.annotations.Queries({
- @javax.jdo.annotations.Query(name = "find", language = "JDOQL", value = "SELECT "
+ @javax.jdo.annotations.Query(name = "find", value = "SELECT "
+ "FROM domainapp.dom.modules.simple.SimpleObject "),
- @javax.jdo.annotations.Query(name = "findByName", language = "JDOQL", value = "SELECT "
+ @javax.jdo.annotations.Query(name = "findByName", value = "SELECT "
+ "FROM domainapp.dom.modules.simple.SimpleObject " + "WHERE name.indexOf(:name) >= 0 ")})
@javax.jdo.annotations.Unique(name = "SimpleObject_name_UNQ", members = {"name"})
@DomainObject
diff --git a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json
index 78b2ac096..998c419f2 100644
--- a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json
+++ b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObject.layout.json
@@ -1,19 +1,3 @@
-/**
- * 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.
- */
{
"columns": [
{
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 03ab30f75..5435325cf 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
@@ -37,12 +37,12 @@ public class SimpleObjectTest {
SimpleObject simpleObject;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
simpleObject = new SimpleObject();
}
@Test
- public void testName() throws Exception {
+ public void testName() {
// given
String name = "Foobar";
assertNull(simpleObject.getName());
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 a95ad5aa3..5fbcfde2b 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
@@ -52,13 +52,13 @@ public class SimpleObjectsTest {
SimpleObjects simpleObjects;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
simpleObjects = new SimpleObjects();
simpleObjects.container = mockContainer;
}
@Test
- public void testCreate() throws Exception {
+ public void testCreate() {
// given
final SimpleObject simpleObject = new SimpleObject();
@@ -85,7 +85,7 @@ public class SimpleObjectsTest {
}
@Test
- public void testListAll() throws Exception {
+ public void testListAll() {
// given
final List all = Lists.newArrayList();
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 dc19195ac..0df939678 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
@@ -67,8 +67,7 @@ public class SimpleObjectCreate extends FixtureScript {
@Override
protected void execute(final ExecutionContext ec) {
-
- String paramName = checkParam("name", ec, String.class);
+ var paramName = checkParam("name", ec, String.class);
this.simpleObject = wrap(simpleObjects).create(paramName);
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 847f15d01..5dc9a4785 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
@@ -27,7 +27,6 @@ import com.google.common.collect.Lists;
import domainapp.dom.modules.simple.SimpleObject;
import domainapp.fixture.modules.simple.SimpleObjectCreate;
import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
-import java.util.Collections;
import java.util.List;
import org.apache.isis.applib.fixturescripts.FixtureScript;
@@ -37,8 +36,18 @@ import org.apache.isis.applib.fixturescripts.FixtureScript;
*/
public class RecreateSimpleObjects extends FixtureScript {
- public final List names = Collections.unmodifiableList(List.of("Foo", "Bar", "Baz",
- "Frodo", "Froyo", "Fizz", "Bip", "Bop", "Bang", "Boo"));
+ public final List names = List.of(
+ "Foo",
+ "Bar",
+ "Baz",
+ "Frodo",
+ "Froyo",
+ "Fizz",
+ "Bip",
+ "Bop",
+ "Bang",
+ "Boo"
+ );
// region > number (optional input)
private Integer number;
@@ -77,7 +86,7 @@ public class RecreateSimpleObjects extends FixtureScript {
protected void execute(final ExecutionContext ec) {
// defaults
- final int paramNumber = defaultParam("number", ec, 3);
+ final var paramNumber = defaultParam("number", ec, 3);
// validate
if (paramNumber < 0 || paramNumber > names.size()) {
@@ -90,8 +99,8 @@ public class RecreateSimpleObjects extends FixtureScript {
//
ec.executeChild(this, new SimpleObjectsTearDown());
- for (int i = 0; i < paramNumber; i++) {
- final SimpleObjectCreate fs = new SimpleObjectCreate().setName(names.get(i));
+ for (var i = 0; i < paramNumber; i++) {
+ final var fs = new SimpleObjectCreate().setName(names.get(i));
ec.executeChild(this, fs.getName(), fs);
simpleObjects.add(fs.getSimpleObject());
}
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 f67c26876..ad186d706 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
@@ -40,7 +40,7 @@ public final class SimpleAppSystemInitializer {
* Init test system
*/
public static void initIsft() {
- IsisSystemForTest isft = IsisSystemForTest.getElseNull();
+ var isft = IsisSystemForTest.getElseNull();
if (isft == null) {
isft = new SimpleAppSystemBuilder().build().setUpSystem();
IsisSystemForTest.set(isft);
@@ -58,8 +58,7 @@ public final class SimpleAppSystemInitializer {
}
private static IsisConfiguration testConfiguration() {
- final IsisConfigurationForJdoIntegTests testConfiguration =
- new IsisConfigurationForJdoIntegTests();
+ final var testConfiguration = new IsisConfigurationForJdoIntegTests();
testConfiguration.addRegisterEntitiesPackagePrefix("domainapp.dom.modules");
return testConfiguration;
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 025c6724a..142b0e9fb 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
@@ -23,10 +23,9 @@
package domainapp.integtests.specglue;
-import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
-
import cucumber.api.java.Before;
import domainapp.fixture.scenarios.RecreateSimpleObjects;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
/**
* Test Execution to append a fixture of SimpleObjects
@@ -34,7 +33,7 @@ import domainapp.fixture.scenarios.RecreateSimpleObjects;
public class CatalogOfFixturesGlue extends CukeGlueAbstract {
@Before(value = {"@integration", "@SimpleObjectsFixture"}, order = 20000)
- public void integrationFixtures() throws Throwable {
+ public void integrationFixtures() {
scenarioExecution().install(new RecreateSimpleObjects());
}
}
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 7b508faf3..51253b667 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
@@ -28,9 +28,7 @@ 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 java.util.List;
import java.util.UUID;
import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
@@ -40,9 +38,9 @@ import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
public class SimpleObjectGlue extends CukeGlueAbstract {
@Given("^there are.* (\\d+) simple objects$")
- public void thereAreNumSimpleObjects(int n) throws Throwable {
+ public void thereAreNumSimpleObjects(int n) {
try {
- final List findAll = service(SimpleObjects.class).listAll();
+ final var findAll = service(SimpleObjects.class).listAll();
assertThat(findAll.size(), is(n));
putVar("list", "all", findAll);
@@ -52,7 +50,7 @@ public class SimpleObjectGlue extends CukeGlueAbstract {
}
@When("^I create a new simple object$")
- public void createNewSimpleObject() throws Throwable {
+ public void createNewSimpleObject() {
service(SimpleObjects.class).create(UUID.randomUUID().toString());
}
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 11ff6a47d..819220344 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
@@ -26,8 +26,10 @@ package domainapp.integtests.tests.modules.simple;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import domainapp.dom.modules.simple.SimpleObject;
+import domainapp.fixture.scenarios.RecreateSimpleObjects;
+import domainapp.integtests.tests.SimpleAppIntegTest;
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;
@@ -35,10 +37,6 @@ import org.apache.isis.applib.services.wrapper.InvalidException;
import org.junit.Before;
import org.junit.Test;
-import domainapp.dom.modules.simple.SimpleObject;
-import domainapp.fixture.scenarios.RecreateSimpleObjects;
-import domainapp.integtests.tests.SimpleAppIntegTest;
-
/**
* Test Fixtures with Simple Objects
*/
@@ -56,7 +54,7 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
private static final String NEW_NAME = "new name";
@Before
- public void setUp() throws Exception {
+ public void setUp() {
// given
fs = new RecreateSimpleObjects().setNumber(1);
fixtureScripts.runFixtureScript(fs, null);
@@ -68,15 +66,15 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testNameAccessible() throws Exception {
- // when
- final String name = simpleObjectWrapped.getName();
+ public void testNameAccessible() {
+ /* when */
+ final var name = simpleObjectWrapped.getName();
// then
assertEquals(fs.names.get(0), name);
}
@Test
- public void testNameCannotBeUpdatedDirectly() throws Exception {
+ public void testNameCannotBeUpdatedDirectly() {
// expect
expectedExceptions.expect(DisabledException.class);
@@ -86,7 +84,7 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testUpdateName() throws Exception {
+ public void testUpdateName() {
// when
simpleObjectWrapped.updateName(NEW_NAME);
@@ -96,7 +94,7 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testUpdateNameFailsValidation() throws Exception {
+ public void testUpdateNameFailsValidation() {
// expect
expectedExceptions.expect(InvalidException.class);
@@ -107,13 +105,13 @@ public class SimpleObjectIntegTest extends SimpleAppIntegTest {
}
@Test
- public void testInterpolatesName() throws Exception {
+ public void testInterpolatesName() {
// given
- final String name = simpleObjectWrapped.getName();
+ final var name = simpleObjectWrapped.getName();
// when
- final String title = container.titleOf(simpleObjectWrapped);
+ final var title = container.titleOf(simpleObjectWrapped);
// then
assertEquals("Object: " + name, title);
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 c762dd88f..2699c5aad 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
@@ -25,11 +25,13 @@ package domainapp.integtests.tests.modules.simple;
import static org.junit.Assert.assertEquals;
+import com.google.common.base.Throwables;
+import domainapp.dom.modules.simple.SimpleObjects;
+import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
+import domainapp.fixture.scenarios.RecreateSimpleObjects;
+import domainapp.integtests.tests.SimpleAppIntegTest;
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;
@@ -37,14 +39,6 @@ import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;
-import com.google.common.base.Throwables;
-
-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;
-
/**
* Fixture Pattern Integration Test
*/
@@ -56,25 +50,25 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
SimpleObjects simpleObjects;
@Test
- public void testListAll() throws Exception {
+ public void testListAll() {
// given
- RecreateSimpleObjects fs = new RecreateSimpleObjects();
+ var fs = new RecreateSimpleObjects();
fixtureScripts.runFixtureScript(fs, null);
nextTransaction();
// when
- final List all = wrap(simpleObjects).listAll();
+ final var all = wrap(simpleObjects).listAll();
// then
assertEquals(fs.getSimpleObjects().size(), all.size());
- SimpleObject simpleObject = wrap(all.get(0));
+ var simpleObject = wrap(all.get(0));
assertEquals(fs.getSimpleObjects().get(0).getName(), simpleObject.getName());
}
-
+
@Test
- public void testListAllWhenNone() throws Exception {
+ public void testListAllWhenNone() {
// given
FixtureScript fs = new SimpleObjectsTearDown();
@@ -82,14 +76,14 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
nextTransaction();
// when
- final List all = wrap(simpleObjects).listAll();
+ final var all = wrap(simpleObjects).listAll();
// then
assertEquals(0, all.size());
}
-
+
@Test
- public void testCreate() throws Exception {
+ public void testCreate() {
// given
FixtureScript fs = new SimpleObjectsTearDown();
@@ -100,12 +94,12 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
wrap(simpleObjects).create("Faz");
// then
- final List all = wrap(simpleObjects).listAll();
+ final var all = wrap(simpleObjects).listAll();
assertEquals(1, all.size());
}
-
+
@Test
- public void testCreateWhenAlreadyExists() throws Exception {
+ public void testCreateWhenAlreadyExists() {
// given
FixtureScript fs = new SimpleObjectsTearDown();
@@ -115,24 +109,22 @@ public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
nextTransaction();
// then
- expectedExceptions.expectCause(causalChainContains(SQLIntegrityConstraintViolationException.class));
+ expectedExceptions
+ .expectCause(causalChainContains(SQLIntegrityConstraintViolationException.class));
// when
wrap(simpleObjects).create("Faz");
nextTransaction();
}
-
+
+ @SuppressWarnings("SameParameterValue")
private static Matcher extends Throwable> causalChainContains(final Class> cls) {
- return new TypeSafeMatcher() {
+ return new TypeSafeMatcher<>() {
@Override
+ @SuppressWarnings("UnstableApiUsage")
protected boolean matchesSafely(Throwable item) {
- final List causalChain = Throwables.getCausalChain(item);
- for (Throwable throwable : causalChain) {
- if (cls.isAssignableFrom(throwable.getClass())) {
- return true;
- }
- }
- return false;
+ final var causalChain = Throwables.getCausalChain(item);
+ return causalChain.stream().map(Throwable::getClass).anyMatch(cls::isAssignableFrom);
}
@Override
diff --git a/naked-objects/webapp/ide/eclipse/launch/.gitignore b/naked-objects/webapp/ide/eclipse/launch/.gitignore
index 3d9734548..3cefd2567 100644
--- a/naked-objects/webapp/ide/eclipse/launch/.gitignore
+++ b/naked-objects/webapp/ide/eclipse/launch/.gitignore
@@ -2,7 +2,3 @@
/SimpleApp-PROTOTYPE-no-fixtures.launch
/SimpleApp-PROTOTYPE-with-fixtures.launch
/SimpleApp-SERVER-no-fixtures.launch
-/SimpleApp-PROTOTYPE-jrebel.launch
-/SimpleApp-PROTOTYPE-no-fixtures.launch
-/SimpleApp-PROTOTYPE-with-fixtures.launch
-/SimpleApp-SERVER-no-fixtures.launch
diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml
index bdf638cba..bbddeb791 100644
--- a/naked-objects/webapp/pom.xml
+++ b/naked-objects/webapp/pom.xml
@@ -129,7 +129,7 @@
-
+
diff --git a/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java b/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
index 8425712dc..780e4027e 100644
--- a/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
+++ b/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
@@ -31,18 +31,15 @@ import com.google.inject.name.Names;
import com.google.inject.util.Modules;
import com.google.inject.util.Providers;
import de.agilecoders.wicket.core.Bootstrap;
-import de.agilecoders.wicket.core.settings.IBootstrapSettings;
import de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchTheme;
import de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchThemeProvider;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
-import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.isis.viewer.wicket.viewer.IsisWicketApplication;
import org.apache.isis.viewer.wicket.viewer.integration.wicket.AuthenticatedWebSessionForIsis;
import org.apache.wicket.Session;
-import org.apache.wicket.request.IRequestParameters;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.http.WebRequest;
@@ -85,7 +82,7 @@ public class SimpleApplication extends IsisWicketApplication {
protected void init() {
super.init();
- IBootstrapSettings settings = Bootstrap.getSettings();
+ var settings = Bootstrap.getSettings();
settings.setThemeProvider(new BootswatchThemeProvider(BootswatchTheme.Flatly));
}
@@ -96,13 +93,10 @@ public class SimpleApplication extends IsisWicketApplication {
}
// else demo mode
- final AuthenticatedWebSessionForIsis s =
- (AuthenticatedWebSessionForIsis) super.newSession(request, response);
- IRequestParameters requestParameters = request.getRequestParameters();
- final org.apache.wicket.util.string.StringValue user =
- requestParameters.getParameterValue("user");
- final org.apache.wicket.util.string.StringValue password =
- requestParameters.getParameterValue("pass");
+ final var s = (AuthenticatedWebSessionForIsis) super.newSession(request, response);
+ var requestParameters = request.getRequestParameters();
+ final var user = requestParameters.getParameterValue("user");
+ final var password = requestParameters.getParameterValue("pass");
s.signIn(user.toString(), password.toString());
return s;
}
@@ -115,7 +109,7 @@ public class SimpleApplication extends IsisWicketApplication {
// else demo mode
try {
- String uname = servletRequest.getParameter("user");
+ var uname = servletRequest.getParameter("user");
if (uname != null) {
servletRequest.getSession().invalidate();
}
@@ -127,7 +121,7 @@ public class SimpleApplication extends IsisWicketApplication {
@Override
protected Module newIsisWicketModule() {
- final Module isisDefaults = super.newIsisWicketModule();
+ final var isisDefaults = super.newIsisWicketModule();
final Module overrides = new AbstractModule() {
@Override
@@ -148,11 +142,11 @@ public class SimpleApplication extends IsisWicketApplication {
return Modules.override(isisDefaults).with(overrides);
}
+ @SuppressWarnings({"UnstableApiUsage", "SameParameterValue"})
private static String readLines(final Class> contextClass, final String resourceName) {
try {
- List readLines =
- Resources.readLines(Resources.getResource(contextClass, resourceName),
- Charset.defaultCharset());
+ var resource = Resources.getResource(contextClass, resourceName);
+ var readLines = Resources.readLines(resource, Charset.defaultCharset());
return Joiner.on("\n").join(readLines);
} catch (IOException e) {
return "This is a simple app";
diff --git a/naked-objects/webapp/src/main/webapp/about/index.html b/naked-objects/webapp/src/main/webapp/about/index.html
index e929c5b6d..4579f3d0b 100644
--- a/naked-objects/webapp/src/main/webapp/about/index.html
+++ b/naked-objects/webapp/src/main/webapp/about/index.html
@@ -110,8 +110,8 @@ th, td {
provides access to a RESTful API conformant with the
- Restful Objects spec. This is part of Apache Isis Core. The
- implementation technology is JBoss RestEasy.
+ Restful Objects spec. This is part of Apache Isis Core.
+ The implementation technology is JBoss RestEasy.
diff --git a/null-object/README.md b/null-object/README.md
index 184e903a0..f5d92a7fc 100644
--- a/null-object/README.md
+++ b/null-object/README.md
@@ -18,6 +18,148 @@ implements the expected interface, but whose method body is empty. The
advantage of this approach over a working default implementation is that a Null
Object is very predictable and has no side effects: it does nothing.
+## Explanation
+
+Real world example
+
+> We are building a binary tree from nodes. There are ordinary nodes and "empty" nodes. Traversing the tree normally should not cause errors, so we use null object pattern where necessary.
+
+In plain words
+
+> Null Object pattern handles "empty" objects gracefully.
+
+Wikipedia says
+
+> In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).
+
+**Programmatic Example**
+
+Here's the definitions for node interface and its implementations.
+
+```java
+public interface Node {
+
+ String getName();
+
+ int getTreeSize();
+
+ Node getLeft();
+
+ Node getRight();
+
+ void walk();
+}
+
+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;
+
+ /**
+ * Constructor.
+ */
+ public NodeImpl(String name, Node left, Node right) {
+ this.name = name;
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public int getTreeSize() {
+ return 1 + left.getTreeSize() + right.getTreeSize();
+ }
+
+ @Override
+ public Node getLeft() {
+ return left;
+ }
+
+ @Override
+ public Node getRight() {
+ return right;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void walk() {
+ LOGGER.info(name);
+ if (left.getTreeSize() > 0) {
+ left.walk();
+ }
+ if (right.getTreeSize() > 0) {
+ right.walk();
+ }
+ }
+}
+
+public final class NullNode implements Node {
+
+ private static final NullNode instance = new NullNode();
+
+ private NullNode() {
+ }
+
+ public static NullNode getInstance() {
+ return instance;
+ }
+
+ @Override
+ public int getTreeSize() {
+ return 0;
+ }
+
+ @Override
+ public Node getLeft() {
+ return null;
+ }
+
+ @Override
+ public Node getRight() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public void walk() {
+ // Do nothing
+ }
+}
+
+```
+
+Then we can construct and traverse the binary tree without errors as follows.
+
+```java
+ var root = new NodeImpl("1",
+ new NodeImpl("11",
+ new NodeImpl("111", NullNode.getInstance(), NullNode.getInstance()),
+ NullNode.getInstance()
+ ),
+ new NodeImpl("12",
+ NullNode.getInstance(),
+ new NodeImpl("122", NullNode.getInstance(), NullNode.getInstance())
+ )
+ );
+ root.walk();
+
+ // 1
+ // 11
+ // 111
+ // 12
+ // 122
+```
+
## Class diagram

diff --git a/null-object/src/main/java/com/iluwatar/nullobject/App.java b/null-object/src/main/java/com/iluwatar/nullobject/App.java
index 2826bafd0..cd35a3042 100644
--- a/null-object/src/main/java/com/iluwatar/nullobject/App.java
+++ b/null-object/src/main/java/com/iluwatar/nullobject/App.java
@@ -37,12 +37,16 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
-
- Node root =
- new NodeImpl("1", new NodeImpl("11", new NodeImpl("111", NullNode.getInstance(),
- NullNode.getInstance()), NullNode.getInstance()), new NodeImpl("12",
- NullNode.getInstance(), new NodeImpl("122", NullNode.getInstance(),
- NullNode.getInstance())));
+ var root = new NodeImpl("1",
+ new NodeImpl("11",
+ new NodeImpl("111", NullNode.getInstance(), NullNode.getInstance()),
+ NullNode.getInstance()
+ ),
+ new NodeImpl("12",
+ NullNode.getInstance(),
+ new NodeImpl("122", NullNode.getInstance(), NullNode.getInstance())
+ )
+ );
root.walk();
}
diff --git a/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java b/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java
index 9b28c249b..472a1a2fd 100644
--- a/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java
+++ b/null-object/src/main/java/com/iluwatar/nullobject/NullNode.java
@@ -30,7 +30,7 @@ package com.iluwatar.nullobject;
*/
public final class NullNode implements Node {
- private static NullNode instance = new NullNode();
+ private static final NullNode instance = new NullNode();
private NullNode() {
}
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java b/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
index 97d6b5eef..754aadc80 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
@@ -26,15 +26,11 @@ package com.iluwatar.nullobject;
import org.junit.jupiter.api.Test;
/**
- *
* Application test
- *
*/
public class AppTest {
-
@Test
public void test() {
- String[] args = {};
- App.main(args);
+ App.main(new String[]{});
}
}
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 b4d9f72d0..aeec371ff 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java
@@ -42,14 +42,14 @@ public class NullNodeTest {
*/
@Test
public void testGetInstance() {
- final NullNode instance = NullNode.getInstance();
+ final var instance = NullNode.getInstance();
assertNotNull(instance);
assertSame(instance, NullNode.getInstance());
}
@Test
public void testFields() {
- final NullNode node = NullNode.getInstance();
+ final var node = NullNode.getInstance();
assertEquals(0, node.getTreeSize());
assertNull(node.getName());
assertNull(node.getLeft());
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 4ff30f524..9a2b485d0 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
@@ -23,22 +23,21 @@
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.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.slf4j.LoggerFactory;
-
-import java.util.LinkedList;
-import java.util.List;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.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.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
/**
* Date: 12/26/15 - 11:44 PM
*
@@ -75,12 +74,12 @@ public class TreeTest {
private static final Node TREE_ROOT;
static {
- final NodeImpl level1B = new NodeImpl("level1_b", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level2B = new NodeImpl("level2_b", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level3A = new NodeImpl("level3_a", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level3B = new NodeImpl("level3_b", NullNode.getInstance(), NullNode.getInstance());
- final NodeImpl level2A = new NodeImpl("level2_a", level3A, level3B);
- final NodeImpl level1A = new NodeImpl("level1_a", level2A, level2B);
+ final var level1B = new NodeImpl("level1_b", NullNode.getInstance(), NullNode.getInstance());
+ final var level2B = new NodeImpl("level2_b", NullNode.getInstance(), NullNode.getInstance());
+ final var level3A = new NodeImpl("level3_a", NullNode.getInstance(), NullNode.getInstance());
+ final var level3B = new NodeImpl("level3_b", NullNode.getInstance(), NullNode.getInstance());
+ final var level2A = new NodeImpl("level2_a", level3A, level3B);
+ final var level1A = new NodeImpl("level1_a", level2A, level2B);
TREE_ROOT = new NodeImpl("root", level1A, level1B);
}
@@ -112,17 +111,17 @@ public class TreeTest {
@Test
public void testGetLeft() {
- final Node level1 = TREE_ROOT.getLeft();
+ final var level1 = TREE_ROOT.getLeft();
assertNotNull(level1);
assertEquals("level1_a", level1.getName());
assertEquals(5, level1.getTreeSize());
- final Node level2 = level1.getLeft();
+ final var level2 = level1.getLeft();
assertNotNull(level2);
assertEquals("level2_a", level2.getName());
assertEquals(3, level2.getTreeSize());
- final Node level3 = level2.getLeft();
+ final var level3 = level2.getLeft();
assertNotNull(level3);
assertEquals("level3_a", level3.getName());
assertEquals(1, level3.getTreeSize());
@@ -132,7 +131,7 @@ public class TreeTest {
@Test
public void testGetRight() {
- final Node level1 = TREE_ROOT.getRight();
+ final var level1 = TREE_ROOT.getRight();
assertNotNull(level1);
assertEquals("level1_b", level1.getName());
assertEquals(1, level1.getTreeSize());
@@ -140,8 +139,8 @@ public class TreeTest {
assertSame(NullNode.getInstance(), level1.getLeft());
}
- private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private static class InMemoryAppender extends AppenderBase {
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
@@ -154,7 +153,7 @@ public class TreeTest {
}
public boolean logContains(String message) {
- return log.stream().anyMatch(event -> event.getMessage().equals(message));
+ return log.stream().map(ILoggingEvent::getMessage).anyMatch(message::equals);
}
public int getLogSize() {
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 4c704f6b1..308760ba9 100644
--- a/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java
+++ b/object-mother/src/main/java/com/iluwatar/objectmother/Queen.java
@@ -66,9 +66,6 @@ public class Queen implements Royalty {
* @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;
+ return this.isFlirty && king.isHappy && !king.isDrunk;
}
}
diff --git a/object-pool/README.md b/object-pool/README.md
index a8a20638c..34d216a02 100644
--- a/object-pool/README.md
+++ b/object-pool/README.md
@@ -36,7 +36,7 @@ Here's the basic Oliphaunt class. These are very expensive to create.
```java
public class Oliphaunt {
- private static AtomicInteger counter = new AtomicInteger(0);
+ private static final AtomicInteger counter = new AtomicInteger(0);
private final int id;
@@ -65,8 +65,8 @@ Next we present the Object Pool and more specifically Oliphaunt Pool.
```java
public abstract class ObjectPool {
- private Set available = new HashSet<>();
- private Set inUse = new HashSet<>();
+ private final Set available = new HashSet<>();
+ private final Set inUse = new HashSet<>();
protected abstract T create();
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 b8ce3cc05..43ac5d873 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
@@ -33,8 +33,8 @@ import java.util.Set;
*/
public abstract class ObjectPool {
- private Set available = new HashSet<>();
- private Set inUse = new HashSet<>();
+ private final Set available = new HashSet<>();
+ private final Set inUse = new HashSet<>();
protected abstract T create();
diff --git a/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java b/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java
index 42db07158..09dedbab0 100644
--- a/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java
+++ b/object-pool/src/main/java/com/iluwatar/object/pool/Oliphaunt.java
@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class Oliphaunt {
- private static AtomicInteger counter = new AtomicInteger(0);
+ private static final AtomicInteger counter = new AtomicInteger(0);
private final int id;
diff --git a/observer/README.md b/observer/README.md
index 034a90e7d..e4b3cea76 100644
--- a/observer/README.md
+++ b/observer/README.md
@@ -13,9 +13,120 @@ tags:
Dependents, Publish-Subscribe
## Intent
-Define a one-to-many dependency between objects so that when one
-object changes state, all its dependents are notified and updated
-automatically.
+Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified
+and updated automatically.
+
+## Explanation
+
+Real world example
+
+> In a land far away lives the races of hobbits and orcs. Both of them are mostly outdoors so they closely follow the changes in weather. One could say that they are constantly observing the weather.
+
+In plain words
+
+> Register as an observer to receive state changes in the object.
+
+Wikipedia says
+
+> The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
+
+**Programmatic Example**
+
+Let's first introduce the weather observer interface and our races, orcs and hobbits.
+
+```java
+public interface WeatherObserver {
+
+ void update(WeatherType currentWeather);
+}
+
+public class Orcs implements WeatherObserver {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class);
+
+ @Override
+ public void update(WeatherType currentWeather) {
+ LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
+ }
+}
+
+public class Hobbits implements WeatherObserver {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class);
+
+ @Override
+ public void update(WeatherType currentWeather) {
+ switch (currentWeather) {
+ LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
+ }
+}
+```
+
+Then here's the weather that is constantly changing.
+
+```java
+public class Weather {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class);
+
+ private WeatherType currentWeather;
+ private final List observers;
+
+ public Weather() {
+ observers = new ArrayList<>();
+ currentWeather = WeatherType.SUNNY;
+ }
+
+ public void addObserver(WeatherObserver obs) {
+ observers.add(obs);
+ }
+
+ public void removeObserver(WeatherObserver obs) {
+ observers.remove(obs);
+ }
+
+ /**
+ * Makes time pass for weather.
+ */
+ public void timePasses() {
+ var enumValues = WeatherType.values();
+ currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
+ LOGGER.info("The weather changed to {}.", currentWeather);
+ notifyObservers();
+ }
+
+ private void notifyObservers() {
+ for (var obs : observers) {
+ obs.update(currentWeather);
+ }
+ }
+}
+```
+
+Here's the full example in action.
+
+```java
+ var weather = new Weather();
+ weather.addObserver(new Orcs());
+ weather.addObserver(new Hobbits());
+
+ weather.timePasses();
+ // The weather changed to rainy.
+ // The orcs are facing rainy weather now
+ // The hobbits are facing rainy weather now
+ weather.timePasses();
+ // The weather changed to windy.
+ // The orcs are facing windy weather now
+ // The hobbits are facing windy weather now
+ weather.timePasses();
+ // The weather changed to cold.
+ // The orcs are facing cold weather now
+ // The hobbits are facing cold weather now
+ weather.timePasses();
+ // The weather changed to sunny.
+ // The orcs are facing sunny weather now
+ // The hobbits are facing sunny weather now
+```
## Class diagram

diff --git a/observer/etc/observer.urm.puml b/observer/etc/observer.urm.puml
index bea9aab53..497ef5fde 100644
--- a/observer/etc/observer.urm.puml
+++ b/observer/etc/observer.urm.puml
@@ -33,7 +33,9 @@ package com.iluwatar.observer {
+ RAINY {static}
+ SUNNY {static}
+ WINDY {static}
+ + description String
+ toString() : String
+ + getDescription() : String
+ valueOf(name : String) : WeatherType {static}
+ values() : WeatherType[] {static}
}
@@ -71,10 +73,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/observer/etc/observer_with_generics.png b/observer/etc/observer_with_generics.png
new file mode 100644
index 000000000..06ff0d9cc
Binary files /dev/null and b/observer/etc/observer_with_generics.png differ
diff --git a/observer/src/main/java/com/iluwatar/observer/Hobbits.java b/observer/src/main/java/com/iluwatar/observer/Hobbits.java
index 646ceebfd..5894c93a6 100644
--- a/observer/src/main/java/com/iluwatar/observer/Hobbits.java
+++ b/observer/src/main/java/com/iluwatar/observer/Hobbits.java
@@ -35,21 +35,6 @@ public class Hobbits implements WeatherObserver {
@Override
public void update(WeatherType currentWeather) {
- switch (currentWeather) {
- case COLD:
- LOGGER.info("The hobbits are shivering in the cold weather.");
- break;
- case RAINY:
- LOGGER.info("The hobbits look for cover from the rain.");
- break;
- case SUNNY:
- LOGGER.info("The happy hobbits bade in the warm sun.");
- break;
- case WINDY:
- LOGGER.info("The hobbits hold their hats tightly in the windy weather.");
- break;
- default:
- break;
- }
+ LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now");
}
}
diff --git a/observer/src/main/java/com/iluwatar/observer/Orcs.java b/observer/src/main/java/com/iluwatar/observer/Orcs.java
index a28ffbc5b..1a955aafd 100644
--- a/observer/src/main/java/com/iluwatar/observer/Orcs.java
+++ b/observer/src/main/java/com/iluwatar/observer/Orcs.java
@@ -35,21 +35,6 @@ public class Orcs implements WeatherObserver {
@Override
public void update(WeatherType currentWeather) {
- switch (currentWeather) {
- case COLD:
- LOGGER.info("The orcs are freezing cold.");
- break;
- case RAINY:
- LOGGER.info("The orcs are dripping wet.");
- break;
- case SUNNY:
- LOGGER.info("The sun hurts the orcs' eyes.");
- break;
- case WINDY:
- LOGGER.info("The orc smell almost vanishes in the wind.");
- break;
- default:
- break;
- }
+ LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now");
}
}
diff --git a/observer/src/main/java/com/iluwatar/observer/Weather.java b/observer/src/main/java/com/iluwatar/observer/Weather.java
index 778858107..a0d80d6bc 100644
--- a/observer/src/main/java/com/iluwatar/observer/Weather.java
+++ b/observer/src/main/java/com/iluwatar/observer/Weather.java
@@ -37,7 +37,7 @@ public class Weather {
private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class);
private WeatherType currentWeather;
- private List observers;
+ private final List observers;
public Weather() {
observers = new ArrayList<>();
diff --git a/observer/src/main/java/com/iluwatar/observer/WeatherType.java b/observer/src/main/java/com/iluwatar/observer/WeatherType.java
index 75ee17d60..e11317c21 100644
--- a/observer/src/main/java/com/iluwatar/observer/WeatherType.java
+++ b/observer/src/main/java/com/iluwatar/observer/WeatherType.java
@@ -28,7 +28,20 @@ package com.iluwatar.observer;
*/
public enum WeatherType {
- SUNNY, RAINY, WINDY, COLD;
+ SUNNY("Sunny"),
+ RAINY("Rainy"),
+ WINDY("Windy"),
+ COLD("Cold");
+
+ private final String description;
+
+ WeatherType(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
@Override
public String toString() {
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 7a555d850..90fd4e300 100644
--- a/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java
+++ b/observer/src/main/java/com/iluwatar/observer/generic/GHobbits.java
@@ -36,21 +36,6 @@ public class GHobbits implements Race {
@Override
public void update(GWeather weather, WeatherType weatherType) {
- switch (weatherType) {
- case COLD:
- LOGGER.info("The hobbits are shivering in the cold weather.");
- break;
- case RAINY:
- LOGGER.info("The hobbits look for cover from the rain.");
- break;
- case SUNNY:
- LOGGER.info("The happy hobbits bade in the warm sun.");
- break;
- case WINDY:
- LOGGER.info("The hobbits hold their hats tightly in the windy weather.");
- break;
- default:
- break;
- }
+ LOGGER.info("The hobbits are facing " + weatherType.getDescription() + " weather now");
}
}
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 d9adbf116..bc49c4e30 100644
--- a/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java
+++ b/observer/src/main/java/com/iluwatar/observer/generic/GOrcs.java
@@ -36,21 +36,6 @@ public class GOrcs implements Race {
@Override
public void update(GWeather weather, WeatherType weatherType) {
- switch (weatherType) {
- case COLD:
- LOGGER.info("The orcs are freezing cold.");
- break;
- case RAINY:
- LOGGER.info("The orcs are dripping wet.");
- break;
- case SUNNY:
- LOGGER.info("The sun hurts the orcs' eyes.");
- break;
- case WINDY:
- LOGGER.info("The orc smell almost vanishes in the wind.");
- break;
- default:
- break;
- }
+ LOGGER.info("The orcs are facing " + weatherType.getDescription() + " weather now");
}
}
diff --git a/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java b/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java
index 66ec45fdb..345b8e331 100644
--- a/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java
@@ -36,10 +36,10 @@ public class HobbitsTest extends WeatherObserverTest {
@Override
public Collection dataProvider() {
return List.of(
- new Object[]{WeatherType.SUNNY, "The happy hobbits bade in the warm sun."},
- new Object[]{WeatherType.RAINY, "The hobbits look for cover from the rain."},
- new Object[]{WeatherType.WINDY, "The hobbits hold their hats tightly in the windy weather."},
- new Object[]{WeatherType.COLD, "The hobbits are shivering in the cold weather."});
+ new Object[]{WeatherType.SUNNY, "The hobbits are facing Sunny weather now"},
+ new Object[]{WeatherType.RAINY, "The hobbits are facing Rainy weather now"},
+ new Object[]{WeatherType.WINDY, "The hobbits are facing Windy weather now"},
+ new Object[]{WeatherType.COLD, "The hobbits are facing Cold weather now"});
}
/**
diff --git a/observer/src/test/java/com/iluwatar/observer/OrcsTest.java b/observer/src/test/java/com/iluwatar/observer/OrcsTest.java
index ff615df3c..65beeaf0e 100644
--- a/observer/src/test/java/com/iluwatar/observer/OrcsTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/OrcsTest.java
@@ -36,10 +36,10 @@ public class OrcsTest extends WeatherObserverTest {
@Override
public Collection dataProvider() {
return List.of(
- new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."},
- new Object[]{WeatherType.RAINY, "The orcs are dripping wet."},
- new Object[]{WeatherType.WINDY, "The orc smell almost vanishes in the wind."},
- new Object[]{WeatherType.COLD, "The orcs are freezing cold."});
+ new Object[]{WeatherType.SUNNY, "The orcs are facing Sunny weather now"},
+ new Object[]{WeatherType.RAINY, "The orcs are facing Rainy weather now"},
+ new Object[]{WeatherType.WINDY, "The orcs are facing Windy weather now"},
+ new Object[]{WeatherType.COLD, "The orcs are facing Cold weather now"});
}
/**
diff --git a/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java b/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java
index dd0e6d6bf..756d72239 100644
--- a/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java
@@ -38,10 +38,10 @@ public class GHobbitsTest extends ObserverTest {
@Override
public Collection dataProvider() {
return List.of(
- new Object[]{WeatherType.SUNNY, "The happy hobbits bade in the warm sun."},
- new Object[]{WeatherType.RAINY, "The hobbits look for cover from the rain."},
- new Object[]{WeatherType.WINDY, "The hobbits hold their hats tightly in the windy weather."},
- new Object[]{WeatherType.COLD, "The hobbits are shivering in the cold weather."}
+ new Object[]{WeatherType.SUNNY, "The hobbits are facing Sunny weather now"},
+ new Object[]{WeatherType.RAINY, "The hobbits are facing Rainy weather now"},
+ new Object[]{WeatherType.WINDY, "The hobbits are facing Windy weather now"},
+ new Object[]{WeatherType.COLD, "The hobbits are facing Cold weather now"}
);
}
diff --git a/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java b/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java
index 396de4456..523678288 100644
--- a/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java
+++ b/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java
@@ -38,10 +38,10 @@ public class OrcsTest extends ObserverTest {
@Override
public Collection dataProvider() {
return List.of(
- new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."},
- new Object[]{WeatherType.RAINY, "The orcs are dripping wet."},
- new Object[]{WeatherType.WINDY, "The orc smell almost vanishes in the wind."},
- new Object[]{WeatherType.COLD, "The orcs are freezing cold."}
+ new Object[]{WeatherType.SUNNY, "The orcs are facing Sunny weather now"},
+ new Object[]{WeatherType.RAINY, "The orcs are facing Rainy weather now"},
+ new Object[]{WeatherType.WINDY, "The orcs are facing Windy weather now"},
+ new Object[]{WeatherType.COLD, "The orcs are facing Cold weather now"}
);
}
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 b3d2bf1bc..132216d19 100644
--- a/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java
+++ b/observer/src/test/java/com/iluwatar/observer/utils/InMemoryAppender.java
@@ -35,7 +35,7 @@ import java.util.List;
* InMemory Log Appender Util.
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
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 779458e05..22bc8a5fb 100644
--- a/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
+++ b/page-object/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumListPageTest {
- private AlbumListPage albumListPage = new AlbumListPage(new WebClient());
+ private final AlbumListPage albumListPage = new AlbumListPage(new WebClient());
@BeforeEach
public void setUp() {
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 601093343..68c836bd3 100644
--- a/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
+++ b/page-object/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumPageTest {
- private AlbumPage albumPage = new AlbumPage(new WebClient());
+ private final AlbumPage albumPage = new AlbumPage(new WebClient());
@BeforeEach
public void setUp() {
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 022f736ca..460bdcf96 100644
--- a/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
+++ b/page-object/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.Test;
*/
public class LoginPageTest {
- private LoginPage loginPage = new LoginPage(new WebClient());
+ private final LoginPage loginPage = new LoginPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
index d1b450a24..1acdd5ba5 100644
--- a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
+++ b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumListPageTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumListPageTest {
- private AlbumListPage albumListPage = new AlbumListPage(new WebClient());
+ private final AlbumListPage albumListPage = new AlbumListPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
index 8e694a592..ecde999c3 100644
--- a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
+++ b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/AlbumPageTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class AlbumPageTest {
- private AlbumPage albumPage = new AlbumPage(new WebClient());
+ private final AlbumPage albumPage = new AlbumPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
index 89668882d..429b7fcc5 100644
--- a/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
+++ b/page-object/test-automation/src/test/java/com/iluwatar/pageobject/LoginPageTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class LoginPageTest {
- private LoginPage loginPage = new LoginPage(new WebClient());
+ private final LoginPage loginPage = new LoginPage(new WebClient());
@BeforeEach
public void setUp() {
diff --git a/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java b/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
index a61a3c429..11a4f23ca 100644
--- a/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
+++ b/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
@@ -30,8 +30,8 @@ import java.util.Map;
* has all video details.
*/
public class VideoResource {
- private FieldJsonMapper fieldJsonMapper;
- private Map videos;
+ private final FieldJsonMapper fieldJsonMapper;
+ private final Map videos;
/**
* Constructor.
diff --git a/pipeline/README.md b/pipeline/README.md
index bc8f9399a..fd03cd7b9 100644
--- a/pipeline/README.md
+++ b/pipeline/README.md
@@ -9,7 +9,83 @@ tags:
---
## Intent
-Allows processing of data in a series of stages by giving in an initial input and passing the processed output to be used by the next stages.
+Allows processing of data in a series of stages by giving in an initial input and passing the processed output to be
+used by the next stages.
+
+## Explanation
+
+The Pipeline pattern uses ordered stages to process a sequence of input values. Each implemented task is represented by
+a stage of the pipeline. You can think of pipelines as similar to assembly lines in a factory, where each item in the
+assembly line is constructed in stages. The partially assembled item is passed from one assembly stage to another. The
+outputs of the assembly line occur in the same order as that of the inputs.
+
+Real world example
+
+> Suppose we wanted to pass through a string to a series of filtering stages and convert it as a char array on the last stage.
+
+In plain words
+
+> Pipeline pattern is an assembly line where partial results are passed from one stage to another.
+
+Wikipedia says
+
+> In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline.
+
+**Programmatic Example**
+
+The stages of our pipeline are called `Handler`s.
+
+```java
+interface Handler {
+ O process(I input);
+}
+```
+
+In our string processing example we have 3 different concrete `Handler`s.
+
+```java
+class RemoveAlphabetsHandler implements Handler {
+ ...
+}
+
+class RemoveDigitsHandler implements Handler {
+ ...
+}
+
+class ConvertToCharArrayHandler implements Handler {
+ ...
+}
+```
+
+Here is the `Pipeline` that will gather and execute the handlers one by one.
+
+```java
+class Pipeline {
+
+ private final Handler currentHandler;
+
+ Pipeline(Handler currentHandler) {
+ this.currentHandler = currentHandler;
+ }
+
+ Pipeline addHandler(Handler newHandler) {
+ return new Pipeline<>(input -> newHandler.process(currentHandler.process(input)));
+ }
+
+ O execute(I input) {
+ return currentHandler.process(input);
+ }
+}
+```
+
+And here's the `Pipeline` in action processing the string.
+
+```java
+ var filters = new Pipeline<>(new RemoveAlphabetsHandler())
+ .addHandler(new RemoveDigitsHandler())
+ .addHandler(new ConvertToCharArrayHandler());
+ filters.execute("GoYankees123!");
+```
## Class diagram

@@ -21,16 +97,16 @@ Use the Pipeline pattern when you want to
* Add readability to complex sequence of operations by providing a fluent builder as an interface
* Improve testability of code since stages will most likely be doing a single thing, complying to the [Single Responsibility Principle (SRP)](https://java-design-patterns.com/principles/#single-responsibility-principle)
-## Typical Use Case
-
-* Implement stages and execute them in an ordered manner
-
-## Real world examples
+## Known uses
* [java.util.Stream](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html)
* [Maven Build Lifecycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
* [Functional Java](https://github.com/functionaljava/functionaljava)
+## Related patterns
+
+* [Chain of Responsibility](https://java-design-patterns.com/patterns/chain/)
+
## Credits
* [The Pipeline Pattern — for fun and profit](https://medium.com/@aaronweatherall/the-pipeline-pattern-for-fun-and-profit-9b5f43a98130)
diff --git a/pipeline/src/main/java/com/iluwatar/pipeline/App.java b/pipeline/src/main/java/com/iluwatar/pipeline/App.java
index 1b1e443e6..cfbcbafc2 100644
--- a/pipeline/src/main/java/com/iluwatar/pipeline/App.java
+++ b/pipeline/src/main/java/com/iluwatar/pipeline/App.java
@@ -59,8 +59,9 @@ public class App {
then is expected to receive an input of char[] array since that is the type being returned
by the previous handler, ConvertToCharArrayHandler.
*/
- new Pipeline<>(new RemoveAlphabetsHandler())
+ var filters = new Pipeline<>(new RemoveAlphabetsHandler())
.addHandler(new RemoveDigitsHandler())
.addHandler(new ConvertToCharArrayHandler());
+ filters.execute("GoYankees123!");
}
}
diff --git a/poison-pill/README.md b/poison-pill/README.md
index 7fd152891..a6cd2fe80 100644
--- a/poison-pill/README.md
+++ b/poison-pill/README.md
@@ -10,8 +10,250 @@ tags:
---
## Intent
-Poison Pill is known predefined data item that allows to provide
-graceful shutdown for separate distributed consumption process.
+Poison Pill is known predefined data item that allows to provide graceful shutdown for separate distributed consumption
+process.
+
+## Explanation
+
+Real world example
+
+> Let's think about a message queue with one producer and one consumer. The producer keeps pushing new messages in the queue and the consumer keeps reading them. Finally when it's time to gracefully shut down the producer sends the poison pill message.
+
+In plain words
+
+> Poison Pill is a known message structure that ends the message exchange.
+
+**Programmatic Example**
+
+Let's define the message structure first.
+
+```java
+public interface Message {
+
+ Message POISON_PILL = new Message() {
+
+ @Override
+ public void addHeader(Headers header, String value) {
+ throw poison();
+ }
+
+ @Override
+ public String getHeader(Headers header) {
+ throw poison();
+ }
+
+ @Override
+ public Map getHeaders() {
+ throw poison();
+ }
+
+ @Override
+ public void setBody(String body) {
+ throw poison();
+ }
+
+ @Override
+ public String getBody() {
+ throw poison();
+ }
+
+ private RuntimeException poison() {
+ return new UnsupportedOperationException("Poison");
+ }
+
+ };
+
+ enum Headers {
+ DATE, SENDER
+ }
+
+ void addHeader(Headers header, String value);
+
+ String getHeader(Headers header);
+
+ Map getHeaders();
+
+ void setBody(String body);
+
+ String getBody();
+}
+
+public class SimpleMessage implements Message {
+
+ private final Map headers = new HashMap<>();
+ private String body;
+
+ @Override
+ public void addHeader(Headers header, String value) {
+ headers.put(header, value);
+ }
+
+ @Override
+ public String getHeader(Headers header) {
+ return headers.get(header);
+ }
+
+ @Override
+ public Map getHeaders() {
+ return Collections.unmodifiableMap(headers);
+ }
+
+ @Override
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ @Override
+ public String getBody() {
+ return body;
+ }
+}
+```
+
+Next we define the types related to the message queue.
+
+```java
+public interface MqPublishPoint {
+
+ void put(Message msg) throws InterruptedException;
+}
+
+public interface MqSubscribePoint {
+
+ Message take() throws InterruptedException;
+}
+
+public interface MessageQueue extends MqPublishPoint, MqSubscribePoint {
+}
+
+public class SimpleMessageQueue implements MessageQueue {
+
+ private final BlockingQueue queue;
+
+ public SimpleMessageQueue(int bound) {
+ queue = new ArrayBlockingQueue<>(bound);
+ }
+
+ @Override
+ public void put(Message msg) throws InterruptedException {
+ queue.put(msg);
+ }
+
+ @Override
+ public Message take() throws InterruptedException {
+ return queue.take();
+ }
+}
+```
+
+Now we need to create the message producer and consumer.
+
+```java
+public class Producer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class);
+
+ private final MqPublishPoint queue;
+ private final String name;
+ private boolean isStopped;
+
+ /**
+ * Constructor.
+ */
+ public Producer(String name, MqPublishPoint queue) {
+ this.name = name;
+ this.queue = queue;
+ this.isStopped = false;
+ }
+
+ /**
+ * Send message to queue.
+ */
+ public void send(String body) {
+ if (isStopped) {
+ throw new IllegalStateException(String.format(
+ "Producer %s was stopped and fail to deliver requested message [%s].", body, name));
+ }
+ var msg = new SimpleMessage();
+ msg.addHeader(Headers.DATE, new Date().toString());
+ msg.addHeader(Headers.SENDER, name);
+ msg.setBody(body);
+
+ try {
+ queue.put(msg);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ }
+ }
+
+ /**
+ * Stop system by sending poison pill.
+ */
+ public void stop() {
+ isStopped = true;
+ try {
+ queue.put(Message.POISON_PILL);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ }
+ }
+}
+
+public class Consumer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class);
+
+ private final MqSubscribePoint queue;
+ private final String name;
+
+ public Consumer(String name, MqSubscribePoint queue) {
+ this.name = name;
+ this.queue = queue;
+ }
+
+ /**
+ * Consume message.
+ */
+ public void consume() {
+ while (true) {
+ try {
+ var msg = queue.take();
+ if (Message.POISON_PILL.equals(msg)) {
+ LOGGER.info("Consumer {} receive request to terminate.", name);
+ break;
+ }
+ var sender = msg.getHeader(Headers.SENDER);
+ var body = msg.getBody();
+ LOGGER.info("Message [{}] from [{}] received by [{}]", body, sender, name);
+ } catch (InterruptedException e) {
+ // allow thread to exit
+ LOGGER.error("Exception caught.", e);
+ return;
+ }
+ }
+ }
+}
+```
+
+Finally we are ready to present the whole example in action.
+
+```java
+ var queue = new SimpleMessageQueue(10000);
+
+ final var producer = new Producer("PRODUCER_1", queue);
+ final var consumer = new Consumer("CONSUMER_1", queue);
+
+ new Thread(consumer::consume).start();
+
+ new Thread(() -> {
+ producer.send("hand shake");
+ producer.send("some very important information");
+ producer.send("bye!");
+ producer.stop();
+ }).start();
+```
## Class diagram

diff --git a/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java b/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java
index 8a7af515f..70d116c9f 100644
--- a/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java
+++ b/poison-pill/src/main/java/com/iluwatar/poison/pill/SimpleMessage.java
@@ -32,7 +32,7 @@ import java.util.Map;
*/
public class SimpleMessage implements Message {
- private Map headers = new HashMap<>();
+ private final Map headers = new HashMap<>();
private String body;
@Override
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 100565fbc..8365fca17 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
@@ -92,7 +92,7 @@ public class ConsumerTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/pom.xml b/pom.xml
index 017bd7e4a..9b3382795 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,7 +58,7 @@
https://sonarcloud.io
iluwatar
iluwatar_java-design-patterns
- ${artifactId}
+ ${project.artifactId}
Java Design Patterns
@@ -376,11 +376,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M3
-
-
- -Xmx1024M ${argLine}
-
+ 3.0.0-M5
org.springframework.boot
@@ -476,8 +472,7 @@
true
-
- ${projectRoot}${file.separator}license-plugin-header-style.xml
+ license-plugin-header-style.xml
SLASHSTAR_CUSTOM_STYLE
@@ -543,14 +538,4 @@
-
-
-
- org.apache.maven.plugins
- maven-jxr-plugin
- 3.0.0
-
-
-
-
diff --git a/priority-queue/README.md b/priority-queue/README.md
index c8d1f7773..924d7169f 100644
--- a/priority-queue/README.md
+++ b/priority-queue/README.md
@@ -6,6 +6,7 @@ permalink: /patterns/priority-queue/
categories: Behavioral
tags:
- Decoupling
+ - Cloud distributed
---
## Intent
@@ -18,12 +19,11 @@ Applications may delegate specific tasks to other services; for example, to perf

## Applicability
-Use the Property pattern when
+Use the Priority Queue pattern when
* The system must handle multiple tasks that might have different priorities.
* Different users or tenants should be served with different priority..
-## Real world examples
+## Credits
-* [ Priority Queue Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589794(v=pandp.10))
-Microsoft Azure does not provide a queuing mechanism that natively support automatic prioritization of messages through sorting. However, it does provide Azure Service Bus topics and subscriptions, which support a queuing mechanism that provides message filtering, together with a wide range of flexible capabilities that make it ideal for use in almost all priority queue implementations.
+* [Priority Queue pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/priority-queue)
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 695424695..d312cd34a 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
@@ -1,50 +1,50 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Immutable stew class, protected with Private Class Data pattern.
- */
-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) {
- data = new StewData(numPotatoes, numCarrots, numMeat, numPeppers);
- }
-
- /**
- * Mix the stew.
- */
- public void mix() {
- LOGGER
- .info("Mixing the immutable stew we find: {} potatoes, {} carrots, {} meat and {} peppers",
- data.getNumPotatoes(), data.getNumCarrots(), data.getNumMeat(), data.getNumPeppers());
- }
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Immutable stew class, protected with Private Class Data pattern.
+ */
+public class ImmutableStew {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ImmutableStew.class);
+
+ private final StewData data;
+
+ public ImmutableStew(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
+ data = new StewData(numPotatoes, numCarrots, numMeat, numPeppers);
+ }
+
+ /**
+ * Mix the stew.
+ */
+ public void mix() {
+ 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/StewData.java b/private-class-data/src/main/java/com/iluwatar/privateclassdata/StewData.java
index bcdaba3e9..1b0fd269b 100644
--- a/private-class-data/src/main/java/com/iluwatar/privateclassdata/StewData.java
+++ b/private-class-data/src/main/java/com/iluwatar/privateclassdata/StewData.java
@@ -1,61 +1,61 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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;
-
-/**
- * Stew ingredients.
- */
-public class StewData {
-
- private int numPotatoes;
- private int numCarrots;
- private int numMeat;
- private int numPeppers;
-
- /**
- * Constructor.
- */
- public StewData(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
- this.numPotatoes = numPotatoes;
- this.numCarrots = numCarrots;
- this.numMeat = numMeat;
- this.numPeppers = numPeppers;
- }
-
- public int getNumPotatoes() {
- return numPotatoes;
- }
-
- public int getNumCarrots() {
- return numCarrots;
- }
-
- public int getNumMeat() {
- return numMeat;
- }
-
- public int getNumPeppers() {
- return numPeppers;
- }
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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;
+
+/**
+ * Stew ingredients.
+ */
+public class StewData {
+
+ private final int numPotatoes;
+ private final int numCarrots;
+ private final int numMeat;
+ private final int numPeppers;
+
+ /**
+ * Constructor.
+ */
+ public StewData(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
+ this.numPotatoes = numPotatoes;
+ this.numCarrots = numCarrots;
+ this.numMeat = numMeat;
+ this.numPeppers = numPeppers;
+ }
+
+ public int getNumPotatoes() {
+ return numPotatoes;
+ }
+
+ public int getNumCarrots() {
+ return numCarrots;
+ }
+
+ public int getNumMeat() {
+ return numMeat;
+ }
+
+ public int getNumPeppers() {
+ return numPeppers;
+ }
+}
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 6fbe638ae..bbcbc8021 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
@@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
* InMemory Log Appender Util.
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java
index 6991ec4d1..89f692282 100644
--- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java
+++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java
@@ -28,9 +28,9 @@ package com.iluwatar.producer.consumer;
*/
public class Item {
- private String producer;
+ private final String producer;
- private int id;
+ private final int id;
public Item(String producer, int id) {
this.id = id;
diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java
index 674fb069a..118e3265d 100644
--- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java
+++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java
@@ -31,7 +31,7 @@ import java.util.concurrent.LinkedBlockingQueue;
*/
public class ItemQueue {
- private BlockingQueue- queue;
+ private final BlockingQueue
- queue;
public ItemQueue() {
diff --git a/promise/README.md b/promise/README.md
index cf3d96c88..993d29a9f 100644
--- a/promise/README.md
+++ b/promise/README.md
@@ -9,18 +9,277 @@ tags:
---
## 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.
+
+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.
+
+## Explanation
+
+The Promise object is used for asynchronous computations. A Promise represents an operation that hasn't completed yet,
+but is expected in the future.
+
+Promises provide a few advantages over callback objects:
+ * Functional composition and error handling
+ * Prevents callback hell and provides callback aggregation
+
+Real world example
+
+> We are developing a software solution that downloads files and calculates the number of lines and character
+frequencies in those files. Promise is an ideal solution to make the code concise and easy to understand.
+
+In plain words
+
+> Promise is a placeholder for an asynchronous operation that is ongoing.
+
+Wikipedia says
+
+> In computer science, future, promise, delay, and deferred refer to constructs used for synchronizing program
+execution in some concurrent programming languages. They describe an object that acts as a proxy for a result that is
+initially unknown, usually because the computation of its value is not yet complete.
+
+**Programmatic Example**
+
+In the example a file is downloaded and its line count is calculated. The calculated line count is then consumed and
+printed on console.
+
+Let's first introduce a support class we need for implementation. Here's `PromiseSupport`.
+
+```java
+class PromiseSupport
implements Future {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PromiseSupport.class);
+
+ private static final int RUNNING = 1;
+ private static final int FAILED = 2;
+ private static final int COMPLETED = 3;
+
+ private final Object lock;
+
+ private volatile int state = RUNNING;
+ private T value;
+ private 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 {
+ synchronized (lock) {
+ while (state == RUNNING) {
+ lock.wait();
+ }
+ }
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
+ }
+
+ @Override
+ public T get(long timeout, TimeUnit unit) throws ExecutionException {
+ synchronized (lock) {
+ while (state == RUNNING) {
+ try {
+ lock.wait(unit.toMillis(timeout));
+ } catch (InterruptedException e) {
+ LOGGER.warn("Interrupted!", e);
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
+ }
+}
+```
+
+With `PromiseSupport` in place we can implement the actual `Promise`.
+
+```java
+public class Promise extends PromiseSupport {
+
+ private Runnable fulfillmentAction;
+ private Consumer super Throwable> exceptionHandler;
+
+ public Promise() {
+ }
+
+ @Override
+ public void fulfill(T value) {
+ super.fulfill(value);
+ postFulfillment();
+ }
+
+ @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;
+ }
+ fulfillmentAction.run();
+ }
+
+ public Promise fulfillInAsync(final Callable task, Executor executor) {
+ executor.execute(() -> {
+ try {
+ fulfill(task.call());
+ } catch (Exception ex) {
+ fulfillExceptionally(ex);
+ }
+ });
+ return this;
+ }
+
+ public Promise thenAccept(Consumer super T> action) {
+ var dest = new Promise();
+ fulfillmentAction = new ConsumeAction(this, dest, action);
+ return dest;
+ }
+
+ public Promise onError(Consumer super Throwable> exceptionHandler) {
+ this.exceptionHandler = exceptionHandler;
+ return this;
+ }
+
+ public Promise thenApply(Function super T, V> func) {
+ Promise dest = new Promise<>();
+ fulfillmentAction = new TransformAction(this, dest, func);
+ return dest;
+ }
+
+ private class ConsumeAction implements Runnable {
+
+ private final Promise src;
+ private final Promise dest;
+ private final Consumer super T> action;
+
+ private ConsumeAction(Promise src, Promise dest, Consumer super T> action) {
+ this.src = src;
+ this.dest = dest;
+ this.action = action;
+ }
+
+ @Override
+ public void run() {
+ try {
+ action.accept(src.get());
+ dest.fulfill(null);
+ } catch (Throwable throwable) {
+ dest.fulfillExceptionally((Exception) throwable.getCause());
+ }
+ }
+ }
+
+ private class TransformAction implements Runnable {
+
+ private final Promise src;
+ private final Promise dest;
+ private final Function super T, V> func;
+
+ private TransformAction(Promise src, Promise dest, Function super T, V> func) {
+ this.src = src;
+ this.dest = dest;
+ this.func = func;
+ }
+
+ @Override
+ public void run() {
+ try {
+ dest.fulfill(func.apply(src.get()));
+ } catch (Throwable throwable) {
+ dest.fulfillExceptionally((Exception) throwable.getCause());
+ }
+ }
+ }
+}
+```
+
+Now we can show the full example in action. Here's how to download and count the number of lines in a file using
+`Promise`.
+
+```java
+ countLines().thenAccept(
+ count -> {
+ LOGGER.info("Line count is: {}", count);
+ taskCompleted();
+ }
+ );
+
+ private Promise countLines() {
+ return download(DEFAULT_URL).thenApply(Utility::countLines);
+ }
+
+ private Promise download(String urlString) {
+ return new Promise()
+ .fulfillInAsync(
+ () -> Utility.downloadFile(urlString), executor)
+ .onError(
+ throwable -> {
+ throwable.printStackTrace();
+ taskCompleted();
+ }
+ );
+ }
+```
## Class diagram
+

## Applicability
+
Promise pattern is applicable in concurrent programming when some work needs to be done asynchronously
and:
@@ -35,10 +294,17 @@ and:
* [Guava ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained)
## Related Patterns
- * Async Method Invocation
- * Callback
+
+ * [Async Method Invocation](https://java-design-patterns.com/patterns/async-method-invocation/)
+ * [Callback](https://java-design-patterns.com/patterns/callback/)
+
+## Tutorials
+
+* [Guide To CompletableFuture](https://www.baeldung.com/java-completablefuture)
## Credits
* [You are missing the point to Promises](https://gist.github.com/domenic/3889970)
* [Functional style callbacks using CompletableFuture](https://www.infoq.com/articles/Functional-Style-Callbacks-Using-CompletableFuture)
+* [Java 8 in Action: Lambdas, Streams, and functional-style programming](https://www.amazon.com/gp/product/1617291994/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617291994&linkId=995af46887bb7b65e6c788a23eaf7146)
+* [Modern Java in Action: Lambdas, streams, functional and reactive programming](https://www.amazon.com/gp/product/1617293563/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617293563&linkId=f70fe0d3e1efaff89554a6479c53759c)
diff --git a/prototype/README.md b/prototype/README.md
index c51f5c9bc..472e8330c 100644
--- a/prototype/README.md
+++ b/prototype/README.md
@@ -10,10 +10,13 @@ tags:
---
## Intent
-Specify the kinds of objects to create using a prototypical
-instance, and create new objects by copying this prototype.
+Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
## Explanation
+
+First it should be noted that Prototype pattern is not used to gain performance benefits. It's only used for creating
+new objects from prototype instance.
+
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.
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java b/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
index 1401460d6..8e2ed9474 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class ElfBeast extends Beast {
- private String helpType;
+ private final String helpType;
public ElfBeast(String helpType) {
this.helpType = helpType;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java b/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
index 4a7eea98f..42a54ca97 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class ElfMage extends Mage {
- private String helpType;
+ private final String helpType;
public ElfMage(String helpType) {
this.helpType = helpType;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java b/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
index 101cd5942..fb426a444 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class ElfWarlord extends Warlord {
- private String helpType;
+ private final String helpType;
public ElfWarlord(String helpType) {
this.helpType = helpType;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java b/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
index eb84b2982..14516f3b4 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
@@ -1,65 +1,65 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.prototype;
-
-/**
- * Concrete factory class.
- */
-public class HeroFactoryImpl implements HeroFactory {
-
- private Mage mage;
- private Warlord warlord;
- private Beast beast;
-
- /**
- * Constructor.
- */
- public HeroFactoryImpl(Mage mage, Warlord warlord, Beast beast) {
- this.mage = mage;
- this.warlord = warlord;
- this.beast = beast;
- }
-
- /**
- * Create mage.
- */
- public Mage createMage() {
- return mage.copy();
- }
-
- /**
- * Create warlord.
- */
- public Warlord createWarlord() {
- return warlord.copy();
- }
-
- /**
- * Create beast.
- */
- public Beast createBeast() {
- return beast.copy();
- }
-
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.prototype;
+
+/**
+ * Concrete factory class.
+ */
+public class HeroFactoryImpl implements HeroFactory {
+
+ private final Mage mage;
+ private final Warlord warlord;
+ private final Beast beast;
+
+ /**
+ * Constructor.
+ */
+ public HeroFactoryImpl(Mage mage, Warlord warlord, Beast beast) {
+ this.mage = mage;
+ this.warlord = warlord;
+ this.beast = beast;
+ }
+
+ /**
+ * Create mage.
+ */
+ public Mage createMage() {
+ return mage.copy();
+ }
+
+ /**
+ * Create warlord.
+ */
+ public Warlord createWarlord() {
+ return warlord.copy();
+ }
+
+ /**
+ * Create beast.
+ */
+ public Beast createBeast() {
+ return beast.copy();
+ }
+
+}
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java b/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
index cf3dc18d8..91339887c 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class OrcBeast extends Beast {
- private String weapon;
+ private final String weapon;
public OrcBeast(String weapon) {
this.weapon = weapon;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java b/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
index cb8239c3f..439e7f368 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class OrcMage extends Mage {
- private String weapon;
+ private final String weapon;
public OrcMage(String weapon) {
this.weapon = weapon;
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java b/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
index 39facc41e..a2ae31b4d 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
@@ -28,7 +28,7 @@ package com.iluwatar.prototype;
*/
public class OrcWarlord extends Warlord {
- private String weapon;
+ private final String weapon;
public OrcWarlord(String weapon) {
this.weapon = weapon;
diff --git a/proxy/README.md b/proxy/README.md
index b89d2a624..ddcc4e784 100644
--- a/proxy/README.md
+++ b/proxy/README.md
@@ -132,12 +132,16 @@ are several common situations in which the Proxy pattern is applicable
* [Controlling Access With Proxy Pattern](http://java-design-patterns.com/blog/controlling-access-with-proxy-pattern/)
-## Real world examples
+## Known uses
* [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
+## Related patterns
+
+* [Ambassador](https://java-design-patterns.com/patterns/ambassador/)
+
## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
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 2187c3300..173825288 100644
--- a/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java
+++ b/proxy/src/test/java/com/iluwatar/proxy/utils/InMemoryAppender.java
@@ -35,7 +35,7 @@ import org.slf4j.LoggerFactory;
* InMemory Log Appender Util.
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/queue-load-leveling/README.md b/queue-load-leveling/README.md
index 3674e7413..5cad88636 100644
--- a/queue-load-leveling/README.md
+++ b/queue-load-leveling/README.md
@@ -7,6 +7,7 @@ categories: Concurrency
tags:
- Decoupling
- Performance
+ - Cloud distributed
---
## Intent
@@ -32,4 +33,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)
+* [Queue-Based Load Leveling pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/queue-based-load-leveling)
diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/App.java b/reactor/src/main/java/com/iluwatar/reactor/app/App.java
index 3bd8176a6..f656eacf6 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/app/App.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/app/App.java
@@ -89,8 +89,8 @@ import java.util.List;
public class App {
private NioReactor reactor;
- private List channels = new ArrayList<>();
- private Dispatcher dispatcher;
+ private final List channels = new ArrayList<>();
+ private final Dispatcher dispatcher;
/**
* Creates an instance of App which will use provided dispatcher for dispatching events on
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 13657cdb2..aba99d65c 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java
@@ -134,7 +134,7 @@ public class NioDatagramChannel extends AbstractNioChannel {
*/
public static class DatagramPacket {
private SocketAddress sender;
- private ByteBuffer data;
+ private final ByteBuffer data;
private SocketAddress receiver;
/**
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 1a0b17386..77e39a88d 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
@@ -228,8 +228,8 @@ public class NioReactor {
* A command that changes the interested operations of the key provided.
*/
class ChangeKeyOpsCommand implements Runnable {
- private SelectionKey key;
- private int interestedOps;
+ private final SelectionKey key;
+ private final int interestedOps;
public ChangeKeyOpsCommand(SelectionKey key, int interestedOps) {
this.key = key;
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 6d705de2f..c54e62e58 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
@@ -34,11 +34,11 @@ public class Reader implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class);
- private Lock readLock;
+ private final Lock readLock;
- private String name;
+ private final String name;
- private long readingTime;
+ private final long readingTime;
/**
* Create new Reader.
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 99c9b056b..932428b4f 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
@@ -59,8 +59,8 @@ public class ReaderWriterLock implements ReadWriteLock {
*/
private final Set globalMutex = new HashSet<>();
- private ReadLock readerLock = new ReadLock();
- private WriteLock writerLock = new WriteLock();
+ private final ReadLock readerLock = new ReadLock();
+ private final WriteLock writerLock = new WriteLock();
@Override
public Lock readLock() {
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 7a971b28b..fbc8321f2 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
@@ -34,11 +34,11 @@ public class Writer implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(Writer.class);
- private Lock writeLock;
+ private final Lock writeLock;
- private String name;
+ private final String name;
- private long writingTime;
+ private final long writingTime;
/**
* Create new Writer who writes for 250ms.
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 c7e8bc02a..01a63d6c8 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
@@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
* InMemory Log Appender Util.
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender(Class clazz) {
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
diff --git a/repository/README.md b/repository/README.md
index 7b5258ea5..ad603ee2b 100644
--- a/repository/README.md
+++ b/repository/README.md
@@ -9,11 +9,236 @@ tags:
---
## Intent
-Repository layer is added between the domain and data mapping
-layers to isolate domain objects from details of the database access code and
-to minimize scattering and duplication of query code. The Repository pattern is
-especially useful in systems where number of domain classes is large or heavy
-querying is utilized.
+Repository layer is added between the domain and data mapping layers to isolate domain objects from details of the
+database access code and to minimize scattering and duplication of query code. The Repository pattern is especially
+useful in systems where number of domain classes is large or heavy querying is utilized.
+
+## Explanation
+Real world example
+
+> Let's say we need a persistent data store for persons. Adding new persons and searching for them according to different criteria must be easy.
+
+In plain words
+
+> Repository architectural pattern creates a uniform layer of data repositories that can be used for CRUD operations.
+
+[Microsoft documentation](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design) says
+
+> Repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer.
+
+**Programmatic Example**
+
+Let's first look at the person class that we need to persist.
+
+```java
+@Entity
+public class Person {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+ private String name;
+ private String surname;
+
+ private int age;
+
+ public Person() {
+ }
+
+ /**
+ * Constructor.
+ */
+ public Person(String name, String surname, int age) {
+ this.name = name;
+ this.surname = surname;
+ this.age = age;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ 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 int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ @Override
+ public String toString() {
+ return "Person [id=" + id + ", name=" + name + ", surname=" + surname + ", age=" + age + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final var prime = 31;
+ var result = 1;
+ result = prime * result + age;
+ result = prime * result + (id == null ? 0 : id.hashCode());
+ result = prime * result + (name == null ? 0 : name.hashCode());
+ result = prime * result + (surname == null ? 0 : surname.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ var other = (Person) obj;
+ if (age != other.age) {
+ return false;
+ }
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ if (surname == null) {
+ return other.surname == null;
+ }
+ return surname.equals(other.surname);
+ }
+}
+```
+
+We are using Spring Data to create the repository so it becomes really simple.
+
+```java
+@Repository
+public interface PersonRepository
+ extends CrudRepository, JpaSpecificationExecutor {
+
+ Person findByName(String name);
+}
+```
+
+Additionally we define a helper class for specification queries.
+
+```java
+public class PersonSpecifications {
+
+ public static class AgeBetweenSpec implements Specification {
+
+ private final int from;
+
+ private final int to;
+
+ public AgeBetweenSpec(int from, int to) {
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
+ return cb.between(root.get("age"), from, to);
+ }
+
+ }
+
+ public static class NameEqualSpec implements Specification {
+
+ public String name;
+
+ public NameEqualSpec(String name) {
+ this.name = name;
+ }
+
+ public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
+ return cb.equal(root.get("name"), this.name);
+ }
+ }
+
+}
+```
+
+And here's the repository in action.
+
+```java
+ var peter = new Person("Peter", "Sagan", 17);
+ var nasta = new Person("Nasta", "Kuzminova", 25);
+ var john = new Person("John", "lawrence", 35);
+ var terry = new Person("Terry", "Law", 36);
+
+ repository.save(peter);
+ repository.save(nasta);
+ repository.save(john);
+ repository.save(terry);
+
+ LOGGER.info("Count Person records: {}", repository.count());
+
+ var persons = (List) repository.findAll();
+ persons.stream().map(Person::toString).forEach(LOGGER::info);
+
+ nasta.setName("Barbora");
+ nasta.setSurname("Spotakova");
+ repository.save(nasta);
+
+ repository.findById(2L).ifPresent(p -> LOGGER.info("Find by id 2: {}", p));
+ repository.deleteById(2L);
+
+ LOGGER.info("Count Person records: {}", repository.count());
+
+ repository
+ .findOne(new PersonSpecifications.NameEqualSpec("John"))
+ .ifPresent(p -> LOGGER.info("Find by John is {}", p));
+
+ persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
+
+ LOGGER.info("Find Person with age between 20,40: ");
+ persons.stream().map(Person::toString).forEach(LOGGER::info);
+
+ repository.deleteAll();
+
+ // Count Person records: 4
+ // Person [id=1, name=Peter, surname=Sagan, age=17]
+ // Person [id=2, name=Nasta, surname=Kuzminova, age=25]
+ // Person [id=3, name=John, surname=lawrence, age=35]
+ // Person [id=4, name=Terry, surname=Law, age=36]
+ // Find by id 2: Person [id=2, name=Barbora, surname=Spotakova, age=25]
+ // Count Person records: 3
+ // Find by John is Person [id=3, name=John, surname=lawrence, age=35]
+ // Find Person with age between 20,40:
+ // Person [id=3, name=John, surname=lawrence, age=35]
+ // Person [id=4, name=Terry, surname=Law, age=36]
+```
## Class diagram

@@ -36,3 +261,4 @@ Use the Repository pattern when
* [Advanced Spring Data JPA - Specifications and Querydsl](https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/)
* [Repository Pattern Benefits and Spring Implementation](https://stackoverflow.com/questions/40068965/repository-pattern-benefits-and-spring-implementation)
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a)
+* [Design patterns that I often avoid: Repository pattern](https://www.infoworld.com/article/3117713/design-patterns-that-i-often-avoid-repository-pattern.html)
diff --git a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
index f91c0a6e1..919b746be 100644
--- a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
+++ b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
@@ -39,9 +39,9 @@ public class PersonSpecifications {
*/
public static class AgeBetweenSpec implements Specification {
- private int from;
+ private final int from;
- private int to;
+ private final int to;
public AgeBetweenSpec(int from, int to) {
this.from = from;
diff --git a/repository/src/test/java/com/iluwatar/repository/AnnotationBasedRepositoryTest.java b/repository/src/test/java/com/iluwatar/repository/AnnotationBasedRepositoryTest.java
index 6b47cbe9a..9e2e1f4e1 100644
--- a/repository/src/test/java/com/iluwatar/repository/AnnotationBasedRepositoryTest.java
+++ b/repository/src/test/java/com/iluwatar/repository/AnnotationBasedRepositoryTest.java
@@ -48,12 +48,12 @@ public class AnnotationBasedRepositoryTest {
@Resource
private PersonRepository repository;
- private Person peter = new Person("Peter", "Sagan", 17);
- private Person nasta = new Person("Nasta", "Kuzminova", 25);
- private Person john = new Person("John", "lawrence", 35);
- private Person terry = new Person("Terry", "Law", 36);
+ private final Person peter = new Person("Peter", "Sagan", 17);
+ private final Person nasta = new Person("Nasta", "Kuzminova", 25);
+ private final Person john = new Person("John", "lawrence", 35);
+ private final Person terry = new Person("Terry", "Law", 36);
- private List persons = List.of(peter, nasta, john, terry);
+ private final List persons = List.of(peter, nasta, john, terry);
/**
* Prepare data for test
diff --git a/repository/src/test/java/com/iluwatar/repository/RepositoryTest.java b/repository/src/test/java/com/iluwatar/repository/RepositoryTest.java
index ad9587aca..77e2b3e35 100644
--- a/repository/src/test/java/com/iluwatar/repository/RepositoryTest.java
+++ b/repository/src/test/java/com/iluwatar/repository/RepositoryTest.java
@@ -48,12 +48,12 @@ public class RepositoryTest {
@Resource
private PersonRepository repository;
- private Person peter = new Person("Peter", "Sagan", 17);
- private Person nasta = new Person("Nasta", "Kuzminova", 25);
- private Person john = new Person("John", "lawrence", 35);
- private Person terry = new Person("Terry", "Law", 36);
+ private final Person peter = new Person("Peter", "Sagan", 17);
+ private final Person nasta = new Person("Nasta", "Kuzminova", 25);
+ private final Person john = new Person("John", "lawrence", 35);
+ private final Person terry = new Person("Terry", "Law", 36);
- private List persons = List.of(peter, nasta, john, terry);
+ private final List persons = List.of(peter, nasta, john, terry);
/**
* Prepare data for test
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 7bba17553..53caabea7 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
@@ -68,7 +68,7 @@ public class ClosableTest {
* Logging Appender Implementation
*/
public class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/retry/README.md b/retry/README.md
index 0f8345412..056674a18 100644
--- a/retry/README.md
+++ b/retry/README.md
@@ -6,18 +6,15 @@ permalink: /patterns/retry/
categories: Behavioral
tags:
- Performance
+ - Cloud distributed
---
-## Retry / resiliency
-Enables an application to handle transient failures from external resources.
-
## Intent
-Transparently retry certain operations that involve communication with external
-resources, particularly over the network, isolating calling code from the
-retry implementation details.
+Transparently retry certain operations that involve communication with external resources, particularly over the
+network, isolating calling code from the retry implementation details.
## Explanation
-The `Retry` pattern consists retrying operations on remote resources over the
+Retry pattern consists retrying operations on remote resources over the
network a set number of times. It closely depends on both business and technical
requirements: how much time will the business allow the end user to wait while
the operation finishes? What are the performance characteristics of the
@@ -30,11 +27,7 @@ Another concern is the impact on the calling code by implementing the retry
mechanism. The retry mechanics should ideally be completely transparent to the
calling code (service interface remains unaltered). There are two general
approaches to this problem: from an enterprise architecture standpoint
-(**strategic**), and a shared library standpoint (**tactical**).
-
-*(As an aside, one interesting property is that, since implementations tend to
-be configurable at runtime, daily monitoring and operation of this capability
-is shifted over to operations support instead of the developers themselves.)*
+(strategic), and a shared library standpoint (tactical).
From a strategic point of view, this would be solved by having requests
be redirected to a separate intermediary system, traditionally an
@@ -42,11 +35,26 @@ be redirected to a separate intermediary system, traditionally an
a [Service Mesh](https://medium.com/microservices-in-practice/service-mesh-for-microservices-2953109a3c9a).
From a tactical point of view, this would be solved by reusing shared libraries
-like [Hystrix](https://github.com/Netflix/Hystrix)[1]. This is the type of
-solution showcased in the simple example that accompanies this *README*.
+like [Hystrix](https://github.com/Netflix/Hystrix) (please note that *Hystrix* is a complete implementation of
+the [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/) pattern, of which the Retry pattern
+can be considered a subset of.). This is the type of solution showcased in the simple example that accompanies this
+*README*.
-In our hypothetical application, we have a generic interface for all
-operations on remote interfaces:
+Real world example
+
+> Our application uses a service providing customer information. Once in a while the service seems to be flaky and can return errors or sometimes it just times out. To circumvent these problems we apply the retry pattern.
+
+In plain words
+
+> Retry pattern transparently retries failed operations over network.
+
+[Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/retry) says
+
+> Enable an application to handle transient failures when it tries to connect to a service or network resource, by transparently retrying a failed operation. This can improve the stability of the application.
+
+**Programmatic Example**
+
+In our hypothetical application, we have a generic interface for all operations on remote interfaces.
```java
public interface BusinessOperation {
@@ -54,8 +62,7 @@ public interface BusinessOperation {
}
```
-And we have an implementation of this interface that finds our customers
-by looking up a database:
+And we have an implementation of this interface that finds our customers by looking up a database.
```java
public final class FindCustomer implements BusinessOperation {
@@ -122,20 +129,12 @@ more importantly we did *not* instruct our `Retry` to ignore, then the operation
would have failed immediately upon receiving the error, not matter how many
attempts were left.
-
-
-[1] Please note that *Hystrix* is a complete implementation of the *Circuit
-Breaker* pattern, of which the *Retry* pattern can be considered a subset of.
-
## Class diagram

## Applicability
-Whenever an application needs to communicate with an external resource,
-particularly in a cloud environment, and if the business requirements allow it.
-
-## Presentations
-You can view Microsoft's article [here](https://docs.microsoft.com/en-us/azure/architecture/patterns/retry).
+Whenever an application needs to communicate with an external resource, particularly in a cloud environment, and if
+the business requirements allow it.
## Consequences
**Pros:**
@@ -150,4 +149,9 @@ You can view Microsoft's article [here](https://docs.microsoft.com/en-us/azure/a
## Related Patterns
-* [Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
+* [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/)
+
+## Credits
+
+* [Retry pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/retry)
+* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications](https://www.amazon.com/gp/product/1621140369/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1621140369&linkId=3e3f686af5e60a7a453b48adb286797b)
diff --git a/role-object/src/main/java/com/iluwatar/roleobject/CustomerCore.java b/role-object/src/main/java/com/iluwatar/roleobject/CustomerCore.java
index 966d0e3f0..1c4cf0383 100644
--- a/role-object/src/main/java/com/iluwatar/roleobject/CustomerCore.java
+++ b/role-object/src/main/java/com/iluwatar/roleobject/CustomerCore.java
@@ -36,7 +36,7 @@ import java.util.Optional;
*/
public class CustomerCore extends Customer {
- private Map roles;
+ private final Map roles;
public CustomerCore() {
roles = new HashMap<>();
diff --git a/role-object/src/main/java/com/iluwatar/roleobject/Role.java b/role-object/src/main/java/com/iluwatar/roleobject/Role.java
index cbc6cc79b..a776178fb 100644
--- a/role-object/src/main/java/com/iluwatar/roleobject/Role.java
+++ b/role-object/src/main/java/com/iluwatar/roleobject/Role.java
@@ -34,7 +34,7 @@ public enum Role {
Borrower(BorrowerRole.class), Investor(InvestorRole.class);
- private Class extends CustomerRole> typeCst;
+ private final Class extends CustomerRole> typeCst;
Role(Class extends CustomerRole> typeCst) {
this.typeCst = typeCst;
diff --git a/saga/README.md b/saga/README.md
index 50aeb7d73..394398f99 100644
--- a/saga/README.md
+++ b/saga/README.md
@@ -46,3 +46,4 @@ Use the Saga pattern, if:
## Credits
- [Pattern: Saga](https://microservices.io/patterns/data/saga.html)
+- [Saga distributed transactions pattern](https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/saga/saga)
diff --git a/saga/src/main/java/com/iluwatar/saga/choreography/Saga.java b/saga/src/main/java/com/iluwatar/saga/choreography/Saga.java
index 818b59a14..506587c76 100644
--- a/saga/src/main/java/com/iluwatar/saga/choreography/Saga.java
+++ b/saga/src/main/java/com/iluwatar/saga/choreography/Saga.java
@@ -33,7 +33,7 @@ import java.util.List;
*/
public class Saga {
- private List chapters;
+ private final List chapters;
private int pos;
private boolean forward;
private boolean finished;
@@ -153,7 +153,7 @@ public class Saga {
* outcoming parameter).
*/
public static class Chapter {
- private String name;
+ private final String name;
private ChapterResult result;
private Object inValue;
diff --git a/saga/src/main/java/com/iluwatar/saga/choreography/ServiceDiscoveryService.java b/saga/src/main/java/com/iluwatar/saga/choreography/ServiceDiscoveryService.java
index a616ff4a5..c6bc7bc80 100644
--- a/saga/src/main/java/com/iluwatar/saga/choreography/ServiceDiscoveryService.java
+++ b/saga/src/main/java/com/iluwatar/saga/choreography/ServiceDiscoveryService.java
@@ -32,7 +32,7 @@ import java.util.Optional;
* The class representing a service discovery pattern.
*/
public class ServiceDiscoveryService {
- private Map services;
+ private final Map services;
/**
* find any service.
diff --git a/saga/src/main/java/com/iluwatar/saga/orchestration/ChapterResult.java b/saga/src/main/java/com/iluwatar/saga/orchestration/ChapterResult.java
index ef34ddb98..b04d22849 100644
--- a/saga/src/main/java/com/iluwatar/saga/orchestration/ChapterResult.java
+++ b/saga/src/main/java/com/iluwatar/saga/orchestration/ChapterResult.java
@@ -29,8 +29,8 @@ package com.iluwatar.saga.orchestration;
* @param incoming value
*/
public class ChapterResult {
- private K value;
- private State state;
+ private final K value;
+ private final State state;
public K getValue() {
return value;
diff --git a/saga/src/main/java/com/iluwatar/saga/orchestration/Saga.java b/saga/src/main/java/com/iluwatar/saga/orchestration/Saga.java
index aff3593f1..1b68d6cf7 100644
--- a/saga/src/main/java/com/iluwatar/saga/orchestration/Saga.java
+++ b/saga/src/main/java/com/iluwatar/saga/orchestration/Saga.java
@@ -32,7 +32,7 @@ import java.util.List;
*/
public class Saga {
- private List chapters;
+ private final List chapters;
private Saga() {
diff --git a/saga/src/main/java/com/iluwatar/saga/orchestration/ServiceDiscoveryService.java b/saga/src/main/java/com/iluwatar/saga/orchestration/ServiceDiscoveryService.java
index dbc6e7eb5..f88efae52 100644
--- a/saga/src/main/java/com/iluwatar/saga/orchestration/ServiceDiscoveryService.java
+++ b/saga/src/main/java/com/iluwatar/saga/orchestration/ServiceDiscoveryService.java
@@ -31,7 +31,7 @@ import java.util.Optional;
* The class representing a service discovery pattern.
*/
public class ServiceDiscoveryService {
- private Map> services;
+ private final Map> services;
public Optional find(String service) {
return Optional.ofNullable(services.getOrDefault(service, null));
diff --git a/saga/src/test/java/com/iluwatar/saga/orchestration/SagaOrchestratorInternallyTest.java b/saga/src/test/java/com/iluwatar/saga/orchestration/SagaOrchestratorInternallyTest.java
index 423b8e12e..f80a46fdc 100644
--- a/saga/src/test/java/com/iluwatar/saga/orchestration/SagaOrchestratorInternallyTest.java
+++ b/saga/src/test/java/com/iluwatar/saga/orchestration/SagaOrchestratorInternallyTest.java
@@ -34,7 +34,7 @@ import org.junit.Test;
*/
public class SagaOrchestratorInternallyTest {
- private List records = new ArrayList<>();
+ private final List records = new ArrayList<>();
@Test
public void executeTest() {
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java b/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java
index d94764dbe..1f4026b92 100644
--- a/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java
+++ b/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java
@@ -35,7 +35,7 @@ public class Fruit {
ORANGE, APPLE, LEMON
}
- private FruitType type;
+ private final FruitType type;
public Fruit(FruitType type) {
this.type = type;
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java b/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java
index 6b43c8100..5c2901efe 100644
--- a/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java
+++ b/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java
@@ -31,7 +31,7 @@ import java.util.List;
*/
public class FruitBowl {
- private List fruit = new ArrayList<>();
+ private final List fruit = new ArrayList<>();
/**
* Returns the amount of fruits left in bowl.
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/FruitShop.java b/semaphore/src/main/java/com/iluwatar/semaphore/FruitShop.java
index a360f955c..c74145610 100644
--- a/semaphore/src/main/java/com/iluwatar/semaphore/FruitShop.java
+++ b/semaphore/src/main/java/com/iluwatar/semaphore/FruitShop.java
@@ -31,7 +31,7 @@ public class FruitShop {
/**
* The FruitBowl instances stored in the class.
*/
- private FruitBowl[] bowls = {
+ private final FruitBowl[] bowls = {
new FruitBowl(),
new FruitBowl(),
new FruitBowl()
@@ -40,7 +40,7 @@ public class FruitShop {
/**
* Access flags for each of the FruitBowl instances.
*/
- private boolean[] available = {
+ private final boolean[] available = {
true,
true,
true
@@ -49,7 +49,7 @@ public class FruitShop {
/**
* The Semaphore that controls access to the class resources.
*/
- private Semaphore semaphore;
+ private final Semaphore semaphore;
/**
* FruitShop constructor.
diff --git a/servant/src/main/java/com/iluwatar/servant/App.java b/servant/src/main/java/com/iluwatar/servant/App.java
index b68cb9aee..9c4591b05 100644
--- a/servant/src/main/java/com/iluwatar/servant/App.java
+++ b/servant/src/main/java/com/iluwatar/servant/App.java
@@ -39,8 +39,8 @@ public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
- private static Servant jenkins = new Servant("Jenkins");
- private static Servant travis = new Servant("Travis");
+ private static final Servant jenkins = new Servant("Jenkins");
+ private static final Servant travis = new Servant("Travis");
/**
* Program entry point.
diff --git a/serverless/src/main/java/com/iluwatar/serverless/baas/api/AbstractDynamoDbHandler.java b/serverless/src/main/java/com/iluwatar/serverless/baas/api/AbstractDynamoDbHandler.java
index a13893f70..abe7c388d 100644
--- a/serverless/src/main/java/com/iluwatar/serverless/baas/api/AbstractDynamoDbHandler.java
+++ b/serverless/src/main/java/com/iluwatar/serverless/baas/api/AbstractDynamoDbHandler.java
@@ -40,7 +40,7 @@ import java.util.Map;
public abstract class AbstractDynamoDbHandler {
private DynamoDBMapper dynamoDbMapper;
- private ObjectMapper objectMapper;
+ private final ObjectMapper objectMapper;
public AbstractDynamoDbHandler() {
this.initAmazonDynamoDb();
diff --git a/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java b/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java
index ef3909adc..a8c729163 100644
--- a/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java
+++ b/serverless/src/test/java/com/iluwatar/serverless/baas/api/SavePersonApiHandlerTest.java
@@ -52,7 +52,7 @@ public class SavePersonApiHandlerTest {
@Mock
private DynamoDBMapper dynamoDbMapper;
- private ObjectMapper objectMapper = new ObjectMapper();
+ private final ObjectMapper objectMapper = new ObjectMapper();
@Before
public void setUp() {
diff --git a/service-layer/README.md b/service-layer/README.md
index 3feaf8395..5e8e49ea6 100644
--- a/service-layer/README.md
+++ b/service-layer/README.md
@@ -9,12 +9,210 @@ tags:
---
## Intent
-Service Layer is an abstraction over domain logic. Typically
-applications require multiple kinds of interfaces to the data they store and
-logic they implement: data loaders, user interfaces, integration gateways, and
-others. Despite their different purposes, these interfaces often need common
-interactions with the application to access and manipulate its data and invoke
-its business logic. The Service Layer fulfills this role.
+
+Service Layer is an abstraction over domain logic. It defines application's boundary with a layer of services that
+establishes a set of available operations and coordinates the application's response in each operation.
+
+## Explanation
+
+Typically applications require different kinds of interfaces to the data they store and the logic they implement.
+Despite their different purposes, these interfaces often need common interactions with the application to access and
+manipulate its data and invoke its business logic. Encoding the logic of the interactions separately in each module
+causes a lot of duplication. It's better to centralize building the business logic inside single Service Layer to avoid
+these pitfalls.
+
+Real world example
+
+> We are writing an application that tracks wizards, spellbooks and spells. Wizards may have spellbooks and spellbooks
+may have spells.
+
+In plain words
+
+> Service Layer is an abstraction over application's business logic.
+
+Wikipedia says
+
+> Service layer is an architectural pattern, applied within the service-orientation design paradigm, which aims to
+organize the services, within a service inventory, into a set of logical layers. Services that are categorized into
+a particular layer share functionality. This helps to reduce the conceptual overhead related to managing the service
+inventory, as the services belonging to the same layer address a smaller set of activities.
+
+**Programmatic Example**
+
+The example application demonstrates interactions between a client `App` and a service `MagicService` that allows
+interaction between wizards, spellbooks and spells. The service is implemented with 3-layer architecture
+(entity, dao, service).
+
+For this explanation we are looking at one vertical slice of the system. Let's start from the entity layer and look at
+`Wizard` class. Other entities not shown here are `Spellbook` and `Spell`.
+
+```java
+@Entity
+@Table(name = "WIZARD")
+public class Wizard extends BaseEntity {
+
+ @Id
+ @GeneratedValue
+ @Column(name = "WIZARD_ID")
+ private Long id;
+
+ private String name;
+
+ @ManyToMany(cascade = CascadeType.ALL)
+ private Set spellbooks;
+
+ public Wizard() {
+ spellbooks = new HashSet<>();
+ }
+
+ public Wizard(String name) {
+ this();
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getSpellbooks() {
+ return spellbooks;
+ }
+
+ public void setSpellbooks(Set spellbooks) {
+ this.spellbooks = spellbooks;
+ }
+
+ public void addSpellbook(Spellbook spellbook) {
+ spellbook.getWizards().add(this);
+ spellbooks.add(spellbook);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
+```
+
+Above the entity layer we have DAOs. For `Wizard` the DAO layer looks as follows.
+
+```java
+public interface WizardDao extends Dao {
+
+ Wizard findByName(String name);
+}
+
+public class WizardDaoImpl extends DaoBaseImpl implements WizardDao {
+
+ @Override
+ public Wizard findByName(String name) {
+ Transaction tx = null;
+ Wizard result;
+ try (var session = getSessionFactory().openSession()) {
+ tx = session.beginTransaction();
+ var criteria = session.createCriteria(persistentClass);
+ criteria.add(Restrictions.eq("name", name));
+ result = (Wizard) criteria.uniqueResult();
+ tx.commit();
+ } catch (Exception e) {
+ if (tx != null) {
+ tx.rollback();
+ }
+ throw e;
+ }
+ return result;
+ }
+}
+```
+
+Next we can look at the Service Layer, which in our case consists of a single `MagicService`.
+
+```java
+public interface MagicService {
+
+ List findAllWizards();
+
+ List findAllSpellbooks();
+
+ List findAllSpells();
+
+ List findWizardsWithSpellbook(String name);
+
+ List findWizardsWithSpell(String name);
+}
+
+public class MagicServiceImpl implements MagicService {
+
+ private final WizardDao wizardDao;
+ private final SpellbookDao spellbookDao;
+ private final SpellDao spellDao;
+
+ public MagicServiceImpl(WizardDao wizardDao, SpellbookDao spellbookDao, SpellDao spellDao) {
+ this.wizardDao = wizardDao;
+ this.spellbookDao = spellbookDao;
+ this.spellDao = spellDao;
+ }
+
+ @Override
+ public List findAllWizards() {
+ return wizardDao.findAll();
+ }
+
+ @Override
+ public List findAllSpellbooks() {
+ return spellbookDao.findAll();
+ }
+
+ @Override
+ public List findAllSpells() {
+ return spellDao.findAll();
+ }
+
+ @Override
+ public List findWizardsWithSpellbook(String name) {
+ var spellbook = spellbookDao.findByName(name);
+ return new ArrayList<>(spellbook.getWizards());
+ }
+
+ @Override
+ public List findWizardsWithSpell(String name) {
+ var spell = spellDao.findByName(name);
+ var spellbook = spell.getSpellbook();
+ return new ArrayList<>(spellbook.getWizards());
+ }
+}
+```
+
+And finally we can show how the client `App` interacts with `MagicService` in the Service Layer.
+
+```java
+ var service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
+ LOGGER.info("Enumerating all wizards");
+ service.findAllWizards().stream().map(Wizard::getName).forEach(LOGGER::info);
+ LOGGER.info("Enumerating all spellbooks");
+ service.findAllSpellbooks().stream().map(Spellbook::getName).forEach(LOGGER::info);
+ LOGGER.info("Enumerating all spells");
+ service.findAllSpells().stream().map(Spell::getName).forEach(LOGGER::info);
+ LOGGER.info("Find wizards with spellbook 'Book of Idores'");
+ var wizardsWithSpellbook = service.findWizardsWithSpellbook("Book of Idores");
+ wizardsWithSpellbook.forEach(w -> LOGGER.info("{} has 'Book of Idores'", w.getName()));
+ LOGGER.info("Find wizards with spell 'Fireball'");
+ var wizardsWithSpell = service.findWizardsWithSpell("Fireball");
+ wizardsWithSpell.forEach(w -> LOGGER.info("{} has 'Fireball'", w.getName()));
+```
+
## Class diagram

diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java
index 962487bd9..cdcf926d0 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java
@@ -37,9 +37,9 @@ import java.util.List;
*/
public class MagicServiceImpl implements MagicService {
- private WizardDao wizardDao;
- private SpellbookDao spellbookDao;
- private SpellDao spellDao;
+ private final WizardDao wizardDao;
+ private final SpellbookDao spellbookDao;
+ private final SpellDao spellDao;
/**
* Constructor.
diff --git a/service-layer/src/main/resources/logback.xml b/service-layer/src/main/resources/logback.xml
index 47fe42236..e6678aff2 100644
--- a/service-layer/src/main/resources/logback.xml
+++ b/service-layer/src/main/resources/logback.xml
@@ -43,6 +43,7 @@
+
diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java
index 60f0f7c03..4e787d34c 100644
--- a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java
+++ b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java
@@ -31,7 +31,7 @@ package com.iluwatar.servicelocator;
*/
public final class ServiceLocator {
- private static ServiceCache serviceCache = new ServiceCache();
+ private static final ServiceCache serviceCache = new ServiceCache();
private ServiceLocator() {
}
diff --git a/sharding/README.md b/sharding/README.md
index 2ee465401..cc2121bb5 100644
--- a/sharding/README.md
+++ b/sharding/README.md
@@ -26,4 +26,4 @@ This pattern offers the following benefits:
## Credits
-* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications - Sharding Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589797(v=pandp.10)?redirectedfrom=MSDN)
+* [Sharding pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/sharding)
diff --git a/sharding/src/main/java/com/iluwatar/sharding/LookupShardManager.java b/sharding/src/main/java/com/iluwatar/sharding/LookupShardManager.java
index 4948c2a19..ce239c156 100644
--- a/sharding/src/main/java/com/iluwatar/sharding/LookupShardManager.java
+++ b/sharding/src/main/java/com/iluwatar/sharding/LookupShardManager.java
@@ -39,7 +39,7 @@ public class LookupShardManager extends ShardManager {
private static final Logger LOGGER = LoggerFactory.getLogger(LookupShardManager.class);
- private Map lookupMap = new HashMap<>();
+ private final Map lookupMap = new HashMap<>();
@Override
public int storeData(Data data) {
diff --git a/sharding/src/main/java/com/iluwatar/sharding/Shard.java b/sharding/src/main/java/com/iluwatar/sharding/Shard.java
index eb0814258..56037bc3a 100644
--- a/sharding/src/main/java/com/iluwatar/sharding/Shard.java
+++ b/sharding/src/main/java/com/iluwatar/sharding/Shard.java
@@ -33,7 +33,7 @@ public class Shard {
private final int id;
- private Map dataStore;
+ private final Map dataStore;
public Shard(final int id) {
this.id = id;
diff --git a/singleton/README.md b/singleton/README.md
index 83f7fb355..60a103a3b 100644
--- a/singleton/README.md
+++ b/singleton/README.md
@@ -34,7 +34,7 @@ Joshua Bloch, Effective Java 2nd Edition p.18
```java
public enum EnumIvoryTower {
- INSTANCE;
+ INSTANCE
}
```
diff --git a/specification/README.md b/specification/README.md
index 6e52bd2e7..6cc0c702f 100644
--- a/specification/README.md
+++ b/specification/README.md
@@ -146,7 +146,7 @@ public abstract class AbstractSelector implements Predicate {
```java
public class ConjunctionSelector extends AbstractSelector {
- private List> leafComponents;
+ private final List> leafComponents;
@SafeVarargs
ConjunctionSelector(AbstractSelector... selectors) {
diff --git a/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java b/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java
index 6b359d8ac..214ae4562 100644
--- a/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java
+++ b/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java
@@ -33,11 +33,11 @@ import com.iluwatar.specification.property.Size;
*/
public abstract class AbstractCreature implements Creature {
- private String name;
- private Size size;
- private Movement movement;
- private Color color;
- private Mass mass;
+ private final String name;
+ private final Size size;
+ private final Movement movement;
+ private final Color color;
+ private final Mass mass;
/**
* Constructor.
diff --git a/specification/src/main/java/com/iluwatar/specification/property/Color.java b/specification/src/main/java/com/iluwatar/specification/property/Color.java
index 6e96b5813..b3128054e 100644
--- a/specification/src/main/java/com/iluwatar/specification/property/Color.java
+++ b/specification/src/main/java/com/iluwatar/specification/property/Color.java
@@ -30,7 +30,7 @@ public enum Color {
DARK("dark"), LIGHT("light"), GREEN("green"), RED("red");
- private String title;
+ private final String title;
Color(String title) {
this.title = title;
diff --git a/specification/src/main/java/com/iluwatar/specification/property/Mass.java b/specification/src/main/java/com/iluwatar/specification/property/Mass.java
index b2d6ddc66..e0e90aa06 100644
--- a/specification/src/main/java/com/iluwatar/specification/property/Mass.java
+++ b/specification/src/main/java/com/iluwatar/specification/property/Mass.java
@@ -28,8 +28,8 @@ package com.iluwatar.specification.property;
*/
public class Mass {
- private double value;
- private String title;
+ private final double value;
+ private final String title;
public Mass(double value) {
this.value = value;
diff --git a/specification/src/main/java/com/iluwatar/specification/property/Movement.java b/specification/src/main/java/com/iluwatar/specification/property/Movement.java
index f76b0584f..fcdcfae70 100644
--- a/specification/src/main/java/com/iluwatar/specification/property/Movement.java
+++ b/specification/src/main/java/com/iluwatar/specification/property/Movement.java
@@ -30,7 +30,7 @@ public enum Movement {
WALKING("walking"), SWIMMING("swimming"), FLYING("flying");
- private String title;
+ private final String title;
Movement(String title) {
this.title = title;
diff --git a/specification/src/main/java/com/iluwatar/specification/property/Size.java b/specification/src/main/java/com/iluwatar/specification/property/Size.java
index 27bc48024..c5ad5525c 100644
--- a/specification/src/main/java/com/iluwatar/specification/property/Size.java
+++ b/specification/src/main/java/com/iluwatar/specification/property/Size.java
@@ -30,7 +30,7 @@ public enum Size {
SMALL("small"), NORMAL("normal"), LARGE("large");
- private String title;
+ private final String title;
Size(String title) {
this.title = title;
diff --git a/specification/src/main/java/com/iluwatar/specification/selector/ConjunctionSelector.java b/specification/src/main/java/com/iluwatar/specification/selector/ConjunctionSelector.java
index bd29aa260..661c8bceb 100644
--- a/specification/src/main/java/com/iluwatar/specification/selector/ConjunctionSelector.java
+++ b/specification/src/main/java/com/iluwatar/specification/selector/ConjunctionSelector.java
@@ -30,7 +30,7 @@ import java.util.List;
*/
public class ConjunctionSelector extends AbstractSelector {
- private List> leafComponents;
+ private final List> leafComponents;
@SafeVarargs
ConjunctionSelector(AbstractSelector... selectors) {
diff --git a/specification/src/main/java/com/iluwatar/specification/selector/DisjunctionSelector.java b/specification/src/main/java/com/iluwatar/specification/selector/DisjunctionSelector.java
index 1fb38a43d..32dcf7e73 100644
--- a/specification/src/main/java/com/iluwatar/specification/selector/DisjunctionSelector.java
+++ b/specification/src/main/java/com/iluwatar/specification/selector/DisjunctionSelector.java
@@ -30,7 +30,7 @@ import java.util.List;
*/
public class DisjunctionSelector extends AbstractSelector {
- private List> leafComponents;
+ private final List> leafComponents;
@SafeVarargs
DisjunctionSelector(AbstractSelector... selectors) {
diff --git a/specification/src/main/java/com/iluwatar/specification/selector/NegationSelector.java b/specification/src/main/java/com/iluwatar/specification/selector/NegationSelector.java
index ad3063000..30302baa2 100644
--- a/specification/src/main/java/com/iluwatar/specification/selector/NegationSelector.java
+++ b/specification/src/main/java/com/iluwatar/specification/selector/NegationSelector.java
@@ -30,7 +30,7 @@ package com.iluwatar.specification.selector;
*/
public class NegationSelector extends AbstractSelector {
- private AbstractSelector component;
+ private final AbstractSelector component;
NegationSelector(AbstractSelector selector) {
this.component = selector;
diff --git a/state/README.md b/state/README.md
index 4f61d3025..a8dd2b5fc 100644
--- a/state/README.md
+++ b/state/README.md
@@ -12,8 +12,126 @@ tags:
Objects for States
## Intent
-Allow an object to alter its behavior when its internal state
-changes. The object will appear to change its class.
+Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
+
+## Explanation
+Real world example
+
+> When observing a mammoth in its natural habitat it seems to change its behavior based on the situation. It may first appear calm but over time when it detects a threat it gets angry and dangerous to its surroundings.
+
+In plain words
+
+> State pattern allows an object to change its behavior.
+
+Wikipedia says
+
+> The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines. The state pattern can be interpreted as a strategy pattern, which is able to switch a strategy through invocations of methods defined in the pattern's interface.
+
+**Programmatic Example**
+
+Here is the state interface and its concrete implementations.
+
+```java
+public interface State {
+
+ void onEnterState();
+
+ void observe();
+}
+
+public class PeacefulState implements State {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PeacefulState.class);
+
+ private final Mammoth mammoth;
+
+ public PeacefulState(Mammoth mammoth) {
+ this.mammoth = mammoth;
+ }
+
+ @Override
+ public void observe() {
+ LOGGER.info("{} is calm and peaceful.", mammoth);
+ }
+
+ @Override
+ public void onEnterState() {
+ LOGGER.info("{} calms down.", mammoth);
+ }
+}
+
+public class AngryState implements State {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AngryState.class);
+
+ private final Mammoth mammoth;
+
+ public AngryState(Mammoth mammoth) {
+ this.mammoth = mammoth;
+ }
+
+ @Override
+ public void observe() {
+ LOGGER.info("{} is furious!", mammoth);
+ }
+
+ @Override
+ public void onEnterState() {
+ LOGGER.info("{} gets angry!", mammoth);
+ }
+}
+```
+
+And here is the mammoth containing the state.
+
+```java
+public class Mammoth {
+
+ private State state;
+
+ public Mammoth() {
+ state = new PeacefulState(this);
+ }
+
+ public void timePasses() {
+ if (state.getClass().equals(PeacefulState.class)) {
+ changeStateTo(new AngryState(this));
+ } else {
+ changeStateTo(new PeacefulState(this));
+ }
+ }
+
+ private void changeStateTo(State newState) {
+ this.state = newState;
+ this.state.onEnterState();
+ }
+
+ @Override
+ public String toString() {
+ return "The mammoth";
+ }
+
+ public void observe() {
+ this.state.observe();
+ }
+}
+```
+
+And here is the full example how the mammoth behaves over time.
+
+```java
+ var mammoth = new Mammoth();
+ mammoth.observe();
+ mammoth.timePasses();
+ mammoth.observe();
+ mammoth.timePasses();
+ mammoth.observe();
+
+ // The mammoth gets angry!
+ // The mammoth is furious!
+ // The mammoth calms down.
+ // The mammoth is calm and peaceful.
+```
## Class diagram

diff --git a/state/src/main/java/com/iluwatar/state/AngryState.java b/state/src/main/java/com/iluwatar/state/AngryState.java
index 8dc296c53..e105262b8 100644
--- a/state/src/main/java/com/iluwatar/state/AngryState.java
+++ b/state/src/main/java/com/iluwatar/state/AngryState.java
@@ -1,52 +1,52 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.state;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Angry state.
- */
-public class AngryState implements State {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(AngryState.class);
-
- private Mammoth mammoth;
-
- public AngryState(Mammoth mammoth) {
- this.mammoth = mammoth;
- }
-
- @Override
- public void observe() {
- LOGGER.info("{} is furious!", mammoth);
- }
-
- @Override
- public void onEnterState() {
- LOGGER.info("{} gets angry!", mammoth);
- }
-
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.state;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Angry state.
+ */
+public class AngryState implements State {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AngryState.class);
+
+ private final Mammoth mammoth;
+
+ public AngryState(Mammoth mammoth) {
+ this.mammoth = mammoth;
+ }
+
+ @Override
+ public void observe() {
+ LOGGER.info("{} is furious!", mammoth);
+ }
+
+ @Override
+ public void onEnterState() {
+ 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 ed83a0738..adf8be209 100644
--- a/state/src/main/java/com/iluwatar/state/PeacefulState.java
+++ b/state/src/main/java/com/iluwatar/state/PeacefulState.java
@@ -1,52 +1,52 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.state;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Peaceful state.
- */
-public class PeacefulState implements State {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(PeacefulState.class);
-
- private Mammoth mammoth;
-
- public PeacefulState(Mammoth mammoth) {
- this.mammoth = mammoth;
- }
-
- @Override
- public void observe() {
- LOGGER.info("{} is calm and peaceful.", mammoth);
- }
-
- @Override
- public void onEnterState() {
- LOGGER.info("{} calms down.", mammoth);
- }
-
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.state;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Peaceful state.
+ */
+public class PeacefulState implements State {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PeacefulState.class);
+
+ private final Mammoth mammoth;
+
+ public PeacefulState(Mammoth mammoth) {
+ this.mammoth = mammoth;
+ }
+
+ @Override
+ public void observe() {
+ LOGGER.info("{} is calm and peaceful.", mammoth);
+ }
+
+ @Override
+ public void onEnterState() {
+ LOGGER.info("{} calms down.", mammoth);
+ }
+
+}
diff --git a/state/src/test/java/com/iluwatar/state/MammothTest.java b/state/src/test/java/com/iluwatar/state/MammothTest.java
index 15624c7ab..4cc6e0adb 100644
--- a/state/src/test/java/com/iluwatar/state/MammothTest.java
+++ b/state/src/test/java/com/iluwatar/state/MammothTest.java
@@ -96,7 +96,7 @@ public class MammothTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java b/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java
index a0c7f84e6..5be38e471 100644
--- a/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java
+++ b/step-builder/src/main/java/com/iluwatar/stepbuilder/CharacterStepBuilder.java
@@ -105,7 +105,7 @@ public final class CharacterStepBuilder {
private String wizardClass;
private String weapon;
private String spell;
- private List abilities = new ArrayList<>();
+ private final List abilities = new ArrayList<>();
@Override
public ClassStep name(String name) {
diff --git a/strangler/README.md b/strangler/README.md
index 2f157f1d2..667940798 100644
--- a/strangler/README.md
+++ b/strangler/README.md
@@ -6,6 +6,7 @@ permalink: /patterns/strangler/
categories: Structural
tags:
- Extensibility
+ - Cloud distributed
---
## Intent
@@ -25,7 +26,5 @@ so usually use it when the system is not so simple.
## Credits
-* [Strangler pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/strangler#context-and-problem)
+* [Strangler pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/strangler)
* [Legacy Application Strangulation : Case Studies](https://paulhammant.com/2013/07/14/legacy-application-strangulation-case-studies/)
-
-
diff --git a/strategy/README.md b/strategy/README.md
index c78753535..21ac1c94b 100644
--- a/strategy/README.md
+++ b/strategy/README.md
@@ -12,9 +12,106 @@ tags:
Policy
## Intent
-Define a family of algorithms, encapsulate each one, and make them
-interchangeable. Strategy lets the algorithm vary independently from clients
-that use it.
+Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary
+independently from clients that use it.
+
+## Explanation
+
+Real world example
+
+> Slaying dragons is a dangerous profession. With experience it becomes easier. Veteran dragonslayers have developed different fighting strategies against different types of dragons.
+
+In plain words
+
+> Strategy pattern allows choosing the best suited algorithm at runtime.
+
+Wikipedia says
+
+> In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime.
+
+**Programmatic Example**
+
+Let's first introduce the dragon slaying strategy interface and its implementations.
+
+```java
+@FunctionalInterface
+public interface DragonSlayingStrategy {
+
+ void execute();
+}
+
+public class MeleeStrategy implements DragonSlayingStrategy {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MeleeStrategy.class);
+
+ @Override
+ public void execute() {
+ LOGGER.info("With your Excalibur you sever the dragon's head!");
+ }
+}
+
+public class ProjectileStrategy implements DragonSlayingStrategy {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ProjectileStrategy.class);
+
+ @Override
+ public void execute() {
+ LOGGER.info("You shoot the dragon with the magical crossbow and it falls dead on the ground!");
+ }
+}
+
+public class SpellStrategy implements DragonSlayingStrategy {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SpellStrategy.class);
+
+ @Override
+ public void execute() {
+ LOGGER.info("You cast the spell of disintegration and the dragon vaporizes in a pile of dust!");
+ }
+}
+```
+
+And here is the mighty dragonslayer who is able to pick his fighting strategy based on the opponent.
+
+```java
+public class DragonSlayer {
+
+ private DragonSlayingStrategy strategy;
+
+ public DragonSlayer(DragonSlayingStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public void changeStrategy(DragonSlayingStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public void goToBattle() {
+ strategy.execute();
+ }
+}
+```
+
+Finally here's dragonslayer in action.
+
+```java
+ LOGGER.info("Green dragon spotted ahead!");
+ var dragonSlayer = new DragonSlayer(new MeleeStrategy());
+ dragonSlayer.goToBattle();
+ LOGGER.info("Red dragon emerges.");
+ dragonSlayer.changeStrategy(new ProjectileStrategy());
+ dragonSlayer.goToBattle();
+ LOGGER.info("Black dragon lands before you.");
+ dragonSlayer.changeStrategy(new SpellStrategy());
+ dragonSlayer.goToBattle();
+
+ // Green dragon spotted ahead!
+ // With your Excalibur you sever the dragon's head!
+ // Red dragon emerges.
+ // You shoot the dragon with the magical crossbow and it falls dead on the ground!
+ // Black dragon lands before you.
+ // You cast the spell of disintegration and the dragon vaporizes in a pile of dust!
+```
## Class diagram

diff --git a/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java
index cca82cefc..0b5a2d615 100644
--- a/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java
+++ b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java
@@ -91,7 +91,7 @@ public class DragonSlayingStrategyTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/template-method/README.md b/template-method/README.md
index e87cfd6de..695644488 100644
--- a/template-method/README.md
+++ b/template-method/README.md
@@ -9,11 +9,115 @@ tags:
---
## Intent
-Define the skeleton of an algorithm in an operation, deferring some
-steps to subclasses. Template method lets subclasses redefine certain steps of
-an algorithm without changing the algorithm's structure.
+Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets
+subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
-To make sure that subclasses don’t override the template method, the template method should be declared `final`.
+## Explanation
+Real world example
+
+> The general steps in stealing an item are the same. First you pick the target, next you confuse him somehow and finally you steal the item. However there are many ways to implement these steps.
+
+In plain words
+
+> Template Method pattern outlines the general steps in the parent class and lets the concrete child implementations define the details.
+
+Wikipedia says
+
+> In object-oriented programming, the template method is one of the behavioral design patterns identified by Gamma et al. in the book Design Patterns. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.
+
+**Programmatic Example**
+
+Let's first introduce the template method class along with its concrete implementations.
+
+```java
+public abstract class StealingMethod {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StealingMethod.class);
+
+ protected abstract String pickTarget();
+
+ protected abstract void confuseTarget(String target);
+
+ protected abstract void stealTheItem(String target);
+
+ public void steal() {
+ var target = pickTarget();
+ LOGGER.info("The target has been chosen as {}.", target);
+ confuseTarget(target);
+ stealTheItem(target);
+ }
+}
+
+public class SubtleMethod extends StealingMethod {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SubtleMethod.class);
+
+ @Override
+ protected String pickTarget() {
+ return "shop keeper";
+ }
+
+ @Override
+ protected void confuseTarget(String target) {
+ LOGGER.info("Approach the {} with tears running and hug him!", target);
+ }
+
+ @Override
+ protected void stealTheItem(String target) {
+ LOGGER.info("While in close contact grab the {}'s wallet.", target);
+ }
+}
+
+public class HitAndRunMethod extends StealingMethod {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HitAndRunMethod.class);
+
+ @Override
+ protected String pickTarget() {
+ return "old goblin woman";
+ }
+
+ @Override
+ protected void confuseTarget(String target) {
+ LOGGER.info("Approach the {} from behind.", target);
+ }
+
+ @Override
+ protected void stealTheItem(String target) {
+ LOGGER.info("Grab the handbag and run away fast!");
+ }
+}
+```
+
+Here's the halfling thief class containing the template method.
+
+```java
+public class HalflingThief {
+
+ private StealingMethod method;
+
+ public HalflingThief(StealingMethod method) {
+ this.method = method;
+ }
+
+ public void steal() {
+ method.steal();
+ }
+
+ public void changeMethod(StealingMethod method) {
+ this.method = method;
+ }
+}
+```
+
+And finally we show how the halfling thief utilizes the different stealing methods.
+
+```java
+ var thief = new HalflingThief(new HitAndRunMethod());
+ thief.steal();
+ thief.changeMethod(new SubtleMethod());
+ thief.steal();
+```
## Class diagram

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 ba6030da4..95326eeec 100644
--- a/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java
+++ b/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java
@@ -146,7 +146,7 @@ public abstract class StealingMethodTest {
}
private class InMemoryAppender extends AppenderBase {
- private List log = new LinkedList<>();
+ private final List log = new LinkedList<>();
public InMemoryAppender() {
((Logger) LoggerFactory.getLogger("root")).addAppender(this);
diff --git a/thread-pool/README.md b/thread-pool/README.md
index 0e125176d..62a2a3339 100644
--- a/thread-pool/README.md
+++ b/thread-pool/README.md
@@ -15,6 +15,146 @@ the system spend more time creating and destroying the threads than executing
the actual tasks. Thread Pool solves this problem by reusing existing threads
and eliminating the latency of creating new threads.
+## Explanation
+Real world example
+
+> We have a large number of relatively short tasks at hand. We need to peel huge amounts of potatoes and serve mighty amount of coffee cups. Creating a new thread for each task would be a waste so we establish a thread pool.
+
+In plain words
+
+> Thread Pool is a concurrency pattern where threads are allocated once and reused between tasks.
+
+Wikipedia says
+
+> In computer programming, a thread pool is a software design pattern for achieving concurrency of execution in a computer program. Often also called a replicated workers or worker-crew model, a thread pool maintains multiple threads waiting for tasks to be allocated for concurrent execution by the supervising program. By maintaining a pool of threads, the model increases performance and avoids latency in execution due to frequent creation and destruction of threads for short-lived tasks. The number of available threads is tuned to the computing resources available to the program, such as a parallel task queue after completion of execution.
+
+**Programmatic Example**
+
+Let's first look at our task hierarchy. We have a base class and then concrete CoffeeMakingTask and PotatoPeelingTask.
+
+```java
+public abstract class Task {
+
+ private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
+
+ private final int id;
+ private final int timeMs;
+
+ public Task(final int timeMs) {
+ this.id = ID_GENERATOR.incrementAndGet();
+ this.timeMs = timeMs;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public int getTimeMs() {
+ return timeMs;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("id=%d timeMs=%d", id, timeMs);
+ }
+}
+
+public class CoffeeMakingTask extends Task {
+
+ private static final int TIME_PER_CUP = 100;
+
+ public CoffeeMakingTask(int numCups) {
+ super(numCups * TIME_PER_CUP);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s", this.getClass().getSimpleName(), super.toString());
+ }
+}
+
+public class PotatoPeelingTask extends Task {
+
+ private static final int TIME_PER_POTATO = 200;
+
+ public PotatoPeelingTask(int numPotatoes) {
+ super(numPotatoes * TIME_PER_POTATO);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s", this.getClass().getSimpleName(), super.toString());
+ }
+}
+```
+
+Next we present a runnable Worker class that the thread pool will utilize to handle all the potato peeling and coffee
+making.
+
+```java
+public class Worker implements Runnable {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class);
+
+ private final Task task;
+
+ public Worker(final Task task) {
+ this.task = task;
+ }
+
+ @Override
+ public void run() {
+ LOGGER.info("{} processing {}", Thread.currentThread().getName(), task.toString());
+ try {
+ Thread.sleep(task.getTimeMs());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
+```
+
+Now we are ready to show the full example in action.
+
+```java
+ LOGGER.info("Program started");
+
+ // Create a list of tasks to be executed
+ var tasks = List.of(
+ new PotatoPeelingTask(3),
+ new PotatoPeelingTask(6),
+ new CoffeeMakingTask(2),
+ new CoffeeMakingTask(6),
+ new PotatoPeelingTask(4),
+ new CoffeeMakingTask(2),
+ new PotatoPeelingTask(4),
+ new CoffeeMakingTask(9),
+ new PotatoPeelingTask(3),
+ new CoffeeMakingTask(2),
+ new PotatoPeelingTask(4),
+ new CoffeeMakingTask(2),
+ new CoffeeMakingTask(7),
+ new PotatoPeelingTask(4),
+ new PotatoPeelingTask(5));
+
+ // Creates a thread pool that reuses a fixed number of threads operating off a shared
+ // unbounded queue. At any point, at most nThreads threads will be active processing
+ // tasks. If additional tasks are submitted when all threads are active, they will wait
+ // in the queue until a thread is available.
+ var executor = Executors.newFixedThreadPool(3);
+
+ // Allocate new worker for each task
+ // The worker is executed when a thread becomes
+ // available in the thread pool
+ tasks.stream().map(Worker::new).forEach(executor::execute);
+ // All tasks were executed, now shutdown
+ executor.shutdown();
+ while (!executor.isTerminated()) {
+ Thread.yield();
+ }
+ LOGGER.info("Program finished");
+```
+
## Class diagram

@@ -22,3 +162,8 @@ and eliminating the latency of creating new threads.
Use the Thread Pool pattern when
* You have a large number of short-lived tasks to be executed in parallel
+
+## Credits
+
+* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0134685997&linkId=e1b9ddd5e669591642c4f30d40cd9f6b)
+* [Java Concurrency in Practice](https://www.amazon.com/gp/product/0321349601/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321349601&linkId=fbedb3bad3c6cbead5afa56eea39ed59)
diff --git a/throttling/README.md b/throttling/README.md
index 12090c5e3..257bce54a 100644
--- a/throttling/README.md
+++ b/throttling/README.md
@@ -6,11 +6,170 @@ permalink: /patterns/throttling/
categories: Behavioral
tags:
- Performance
+ - Cloud distributed
---
## Intent
Ensure that a given client is not able to access service resources more than the assigned limit.
+## Explanation
+Real world example
+
+> A large multinational corporation offers API to its customers. The API is rate-limited and each customer can only make certain amount of calls per second.
+
+In plain words
+
+> Throttling pattern is used to rate-limit access to a resource.
+
+[Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling) says
+
+> Control the consumption of resources used by an instance of an application, an individual tenant, or an entire service. This can allow the system to continue to function and meet service level agreements, even when an increase in demand places an extreme load on resources.
+
+**Programmatic Example**
+
+Tenant class presents the clients of the API. CallsCount tracks the number of API calls per tenant.
+
+```java
+public class Tenant {
+
+ private final String name;
+ private final int allowedCallsPerSecond;
+
+ public Tenant(String name, int allowedCallsPerSecond, CallsCount callsCount) {
+ if (allowedCallsPerSecond < 0) {
+ throw new InvalidParameterException("Number of calls less than 0 not allowed");
+ }
+ this.name = name;
+ this.allowedCallsPerSecond = allowedCallsPerSecond;
+ callsCount.addTenant(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAllowedCallsPerSecond() {
+ return allowedCallsPerSecond;
+ }
+}
+
+public final class CallsCount {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CallsCount.class);
+ private final Map tenantCallsCount = new ConcurrentHashMap<>();
+
+ public void addTenant(String tenantName) {
+ tenantCallsCount.putIfAbsent(tenantName, new AtomicLong(0));
+ }
+
+ public void incrementCount(String tenantName) {
+ tenantCallsCount.get(tenantName).incrementAndGet();
+ }
+
+ public long getCount(String tenantName) {
+ return tenantCallsCount.get(tenantName).get();
+ }
+
+ public void reset() {
+ LOGGER.debug("Resetting the map.");
+ tenantCallsCount.replaceAll((k, v) -> new AtomicLong(0));
+ }
+}
+```
+
+Next we introduce the service that the tenants are calling. To track the call count we use the throttler timer.
+
+```java
+public interface Throttler {
+
+ void start();
+}
+
+public class ThrottleTimerImpl implements Throttler {
+
+ private final int throttlePeriod;
+ private final CallsCount callsCount;
+
+ public ThrottleTimerImpl(int throttlePeriod, CallsCount callsCount) {
+ this.throttlePeriod = throttlePeriod;
+ this.callsCount = callsCount;
+ }
+
+ @Override
+ public void start() {
+ new Timer(true).schedule(new TimerTask() {
+ @Override
+ public void run() {
+ callsCount.reset();
+ }
+ }, 0, throttlePeriod);
+ }
+}
+
+class B2BService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(B2BService.class);
+ private final CallsCount callsCount;
+
+ public B2BService(Throttler timer, CallsCount callsCount) {
+ this.callsCount = callsCount;
+ timer.start();
+ }
+
+ public int dummyCustomerApi(Tenant tenant) {
+ var tenantName = tenant.getName();
+ var count = callsCount.getCount(tenantName);
+ LOGGER.debug("Counter for {} : {} ", tenant.getName(), count);
+ if (count >= tenant.getAllowedCallsPerSecond()) {
+ LOGGER.error("API access per second limit reached for: {}", tenantName);
+ return -1;
+ }
+ callsCount.incrementCount(tenantName);
+ return getRandomCustomerId();
+ }
+
+ private int getRandomCustomerId() {
+ return ThreadLocalRandom.current().nextInt(1, 10000);
+ }
+}
+```
+
+Now we are ready to see the full example in action. Tenant Adidas is rate-limited to 5 calls per second and Nike to 6.
+
+```java
+ public static void main(String[] args) {
+ var callsCount = new CallsCount();
+ var adidas = new Tenant("Adidas", 5, callsCount);
+ var nike = new Tenant("Nike", 6, callsCount);
+
+ var executorService = Executors.newFixedThreadPool(2);
+ executorService.execute(() -> makeServiceCalls(adidas, callsCount));
+ executorService.execute(() -> makeServiceCalls(nike, callsCount));
+ executorService.shutdown();
+
+ try {
+ executorService.awaitTermination(10, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ LOGGER.error("Executor Service terminated: {}", e.getMessage());
+ }
+ }
+
+ private static void makeServiceCalls(Tenant tenant, CallsCount callsCount) {
+ var timer = new ThrottleTimerImpl(10, callsCount);
+ var service = new B2BService(timer, callsCount);
+ // Sleep is introduced to keep the output in check and easy to view and analyze the results.
+ IntStream.range(0, 20).forEach(i -> {
+ service.dummyCustomerApi(tenant);
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ LOGGER.error("Thread interrupted: {}", e.getMessage());
+ }
+ });
+ }
+```
+
+
## Class diagram

@@ -19,3 +178,8 @@ The Throttling pattern should be used:
* When a service access needs to be restricted to not have high impacts on the performance of the service.
* When multiple clients are consuming the same service resources and restriction has to be made according to the usage per client.
+
+## Credits
+
+* [Throttling pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling)
+* [Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications (Microsoft patterns & practices)](https://www.amazon.com/gp/product/B00ITGHBBS/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B00ITGHBBS&linkId=12aacdd0cec04f372e7152689525631a)
diff --git a/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java b/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java
index 8f8036286..abfd4d351 100644
--- a/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java
+++ b/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java
@@ -38,7 +38,7 @@ import org.slf4j.LoggerFactory;
public final class CallsCount {
private static final Logger LOGGER = LoggerFactory.getLogger(CallsCount.class);
- private Map tenantCallsCount = new ConcurrentHashMap<>();
+ private final Map tenantCallsCount = new ConcurrentHashMap<>();
/**
* Add a new tenant to the map.
diff --git a/throttling/src/main/java/com/iluwatar/throttling/Tenant.java b/throttling/src/main/java/com/iluwatar/throttling/Tenant.java
index d94344428..5fe2c72db 100644
--- a/throttling/src/main/java/com/iluwatar/throttling/Tenant.java
+++ b/throttling/src/main/java/com/iluwatar/throttling/Tenant.java
@@ -30,8 +30,8 @@ import java.security.InvalidParameterException;
*/
public class Tenant {
- private String name;
- private int allowedCallsPerSecond;
+ private final String name;
+ private final int allowedCallsPerSecond;
/**
* Constructor.
diff --git a/throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java b/throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java
index 6a328c3f0..786325237 100644
--- a/throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java
+++ b/throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java
@@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test;
*/
public class B2BServiceTest {
- private CallsCount callsCount = new CallsCount();
+ private final CallsCount callsCount = new CallsCount();
@Test
public void dummyCustomerApiTest() {
diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java
index c4e885896..4e5c14e0b 100644
--- a/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java
+++ b/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java
@@ -1,93 +1,93 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.tls;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.concurrent.Callable;
-import java.util.stream.IntStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 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 {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(DateFormatCallable.class);
- // 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 var idf = inDateFormat; //TLTL
- this.df = ThreadLocal.withInitial(() -> { //TLTL
- return new SimpleDateFormat(idf); //TLTL
- }); //TLTL
- // this.df = new SimpleDateFormat(inDateFormat); //NTLNTL
- this.dateValue = inDateValue;
- }
-
- @Override
- public Result call() {
- LOGGER.info(Thread.currentThread() + " started executing...");
- var result = new Result();
-
- // Convert date value to date 5 times
- IntStream.rangeClosed(1, 5).forEach(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());
- }
- });
-
- LOGGER.info(Thread.currentThread() + " finished processing part of the thread");
-
- return result;
- }
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.tls;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.concurrent.Callable;
+import java.util.stream.IntStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 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 {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DateFormatCallable.class);
+ // class variables (members)
+ private final ThreadLocal df; //TLTL
+ // private DateFormat df; //NTLNTL
+
+ private final 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 var idf = inDateFormat; //TLTL
+ this.df = ThreadLocal.withInitial(() -> { //TLTL
+ return new SimpleDateFormat(idf); //TLTL
+ }); //TLTL
+ // this.df = new SimpleDateFormat(inDateFormat); //NTLNTL
+ this.dateValue = inDateValue;
+ }
+
+ @Override
+ public Result call() {
+ LOGGER.info(Thread.currentThread() + " started executing...");
+ var result = new Result();
+
+ // Convert date value to date 5 times
+ IntStream.rangeClosed(1, 5).forEach(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());
+ }
+ });
+
+ LOGGER.info(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
index c98a07b91..38dc197cf 100644
--- a/tls/src/main/java/com/iluwatar/tls/Result.java
+++ b/tls/src/main/java/com/iluwatar/tls/Result.java
@@ -1,65 +1,65 @@
-/*
- * The MIT License
- * Copyright © 2014-2019 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.
- */
-
-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<>();
-
- /**
- * Get list of date values collected within a thread execution.
- *
- * @return List of date values collected within an thread execution
- */
- public List getDateList() {
- return dateList;
- }
-
- /**
- * Get list of exceptions thrown within a thread execution.
- *
- * @return List of exceptions thrown within an thread execution
- */
- public List getExceptionList() {
- return exceptionList;
- }
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2019 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.
+ */
+
+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 final List dateList = new ArrayList<>();
+
+ // A list to collect Exceptions thrown in one threads (should be none in
+ // this example)
+ private final List exceptionList = new ArrayList<>();
+
+ /**
+ * Get list of date values collected within a thread execution.
+ *
+ * @return List of date values collected within an thread execution
+ */
+ public List getDateList() {
+ return dateList;
+ }
+
+ /**
+ * Get list of exceptions thrown within a thread execution.
+ *
+ * @return List of exceptions thrown within an thread execution
+ */
+ public List getExceptionList() {
+ return exceptionList;
+ }
+}
diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java
index 48e5854a3..5338829d0 100644
--- a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java
+++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java
@@ -66,18 +66,18 @@ public class DateFormatCallableTest {
/**
* Expected number of date values in the date value list created by the run of DateFormatRunnalbe
*/
- private int expectedCounterDateValues = 5;
+ private final int expectedCounterDateValues = 5;
/**
* Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe.
*/
- private int expectedCounterExceptions = 0;
+ private final int expectedCounterExceptions = 0;
/**
* Expected content of the list containing the date values created by the run of
* DateFormatRunnalbe
*/
- private List expectedDateValues =
+ private final List expectedDateValues =
List.of("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015");
/**
diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java
index 8b02faf0b..7b3d6b4ad 100644
--- a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java
+++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java
@@ -54,18 +54,18 @@ public class DateFormatCallableTestIncorrectDateFormat {
/**
* Expected number of date values in the date value list created by the run of DateFormatRunnalbe
*/
- private int expectedCounterDateValues = 0;
+ private final int expectedCounterDateValues = 0;
/**
* Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe.
*/
- private int expectedCounterExceptions = 5;
+ private final int expectedCounterExceptions = 5;
/**
* Expected content of the list containing the exceptions created by the run of
* DateFormatRunnalbe
*/
- private List expectedExceptions = List.of(
+ private final List expectedExceptions = List.of(
"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\"",
diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java
index c0e8e1844..b3328d4c5 100644
--- a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java
+++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java
@@ -55,7 +55,7 @@ public class DateFormatCallableTestMultiThread {
* Result object given back by DateFormatCallable, one for each thread -- Array with converted
* date values -- Array with thrown exceptions
*/
- private static Result[] result = new Result[4];
+ private static final Result[] result = new Result[4];
/**
* The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup()
@@ -66,22 +66,22 @@ public class DateFormatCallableTestMultiThread {
/* nothing needed here */
}
- private static List[] createdDateValues = new StringArrayList[4];
+ private static final List[] createdDateValues = new StringArrayList[4];
/**
* Expected number of date values in the date value list created by each thread
*/
- private int expectedCounterDateValues = 5;
+ private final int expectedCounterDateValues = 5;
/**
* Expected number of exceptions in the exception list created by each thread
*/
- private int expectedCounterExceptions = 0;
+ private final int expectedCounterExceptions = 0;
/**
* Expected content of the list containing the date values created by each thread
*/
- private List expectedDateValues =
+ private final List expectedDateValues =
List.of("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015");
/**
diff --git a/tolerant-reader/README.md b/tolerant-reader/README.md
index c60e75707..922de90de 100644
--- a/tolerant-reader/README.md
+++ b/tolerant-reader/README.md
@@ -9,10 +9,189 @@ tags:
---
## Intent
-Tolerant Reader is an integration pattern that helps creating
-robust communication systems. The idea is to be as tolerant as possible when
-reading data from another service. This way, when the communication schema
-changes, the readers must not break.
+Tolerant Reader is an integration pattern that helps creating robust communication systems. The idea is to be as
+tolerant as possible when reading data from another service. This way, when the communication schema changes, the
+readers must not break.
+
+## Explanation
+Real world example
+
+> We are persisting rainbowfish objects to file and later on they need to be restored. What makes it problematic is that rainbowfish data structure is versioned and evolves over time. New version of rainbowfish needs to be able to restore old versions as well.
+
+In plain words
+
+> Tolerant Reader pattern is used to create robust communication mechanisms between services.
+
+[Robustness Principle](https://java-design-patterns.com/principles/#robustness-principle) says
+
+> Be conservative in what you do, be liberal in what you accept from others
+
+**Programmatic Example**
+
+Here's the versioned rainbowfish. Notice how the second version introduces additional properties.
+
+```java
+public class RainbowFish implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String name;
+ private final int age;
+ private final int lengthMeters;
+ private final int weightTons;
+
+ /**
+ * Constructor.
+ */
+ public RainbowFish(String name, int age, int lengthMeters, int weightTons) {
+ this.name = name;
+ this.age = age;
+ this.lengthMeters = lengthMeters;
+ this.weightTons = weightTons;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public int getLengthMeters() {
+ return lengthMeters;
+ }
+
+ public int getWeightTons() {
+ return weightTons;
+ }
+}
+
+public class RainbowFishV2 extends RainbowFish {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean sleeping;
+ private boolean hungry;
+ private boolean angry;
+
+ public RainbowFishV2(String name, int age, int lengthMeters, int weightTons) {
+ super(name, age, lengthMeters, weightTons);
+ }
+
+ /**
+ * Constructor.
+ */
+ public RainbowFishV2(String name, int age, int lengthMeters, int weightTons, boolean sleeping,
+ boolean hungry, boolean angry) {
+ this(name, age, lengthMeters, weightTons);
+ this.sleeping = sleeping;
+ this.hungry = hungry;
+ this.angry = angry;
+ }
+
+ public boolean getSleeping() {
+ return sleeping;
+ }
+
+ public boolean getHungry() {
+ return hungry;
+ }
+
+ public boolean getAngry() {
+ return angry;
+ }
+}
+```
+
+Next we introduce the rainbowfish serializer. This is the class that implements the Tolerant Reader pattern.
+
+```java
+public final class RainbowFishSerializer {
+
+ private RainbowFishSerializer() {
+ }
+
+ public static void writeV1(RainbowFish rainbowFish, String filename) throws IOException {
+ var map = Map.of(
+ "name", rainbowFish.getName(),
+ "age", String.format("%d", rainbowFish.getAge()),
+ "lengthMeters", String.format("%d", rainbowFish.getLengthMeters()),
+ "weightTons", String.format("%d", rainbowFish.getWeightTons())
+ );
+
+ try (var fileOut = new FileOutputStream(filename);
+ var objOut = new ObjectOutputStream(fileOut)) {
+ objOut.writeObject(map);
+ }
+ }
+
+ public static void writeV2(RainbowFishV2 rainbowFish, String filename) throws IOException {
+ var map = Map.of(
+ "name", rainbowFish.getName(),
+ "age", String.format("%d", rainbowFish.getAge()),
+ "lengthMeters", String.format("%d", rainbowFish.getLengthMeters()),
+ "weightTons", String.format("%d", rainbowFish.getWeightTons()),
+ "angry", Boolean.toString(rainbowFish.getAngry()),
+ "hungry", Boolean.toString(rainbowFish.getHungry()),
+ "sleeping", Boolean.toString(rainbowFish.getSleeping())
+ );
+
+ try (var fileOut = new FileOutputStream(filename);
+ var objOut = new ObjectOutputStream(fileOut)) {
+ objOut.writeObject(map);
+ }
+ }
+
+ public static RainbowFish readV1(String filename) throws IOException, ClassNotFoundException {
+ Map map;
+
+ try (var fileIn = new FileInputStream(filename);
+ var 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"))
+ );
+ }
+}
+```
+
+And finally here's the full example in action.
+
+```java
+ var fishV1 = new RainbowFish("Zed", 10, 11, 12);
+ LOGGER.info("fishV1 name={} age={} length={} weight={}", fishV1.getName(),
+ fishV1.getAge(), fishV1.getLengthMeters(), fishV1.getWeightTons());
+ RainbowFishSerializer.writeV1(fishV1, "fish1.out");
+
+ var deserializedRainbowFishV1 = RainbowFishSerializer.readV1("fish1.out");
+ LOGGER.info("deserializedFishV1 name={} age={} length={} weight={}",
+ deserializedRainbowFishV1.getName(), deserializedRainbowFishV1.getAge(),
+ deserializedRainbowFishV1.getLengthMeters(), deserializedRainbowFishV1.getWeightTons());
+
+ var fishV2 = new RainbowFishV2("Scar", 5, 12, 15, true, true, true);
+ LOGGER.info(
+ "fishV2 name={} age={} length={} weight={} sleeping={} hungry={} angry={}",
+ fishV2.getName(), fishV2.getAge(), fishV2.getLengthMeters(), fishV2.getWeightTons(),
+ fishV2.getHungry(), fishV2.getAngry(), fishV2.getSleeping());
+ RainbowFishSerializer.writeV2(fishV2, "fish2.out");
+
+ var deserializedFishV2 = RainbowFishSerializer.readV1("fish2.out");
+ LOGGER.info("deserializedFishV2 name={} age={} length={} weight={}",
+ deserializedFishV2.getName(), deserializedFishV2.getAge(),
+ deserializedFishV2.getLengthMeters(), deserializedFishV2.getWeightTons());
+
+ // fishV1 name=Zed age=10 length=11 weight=12
+ // deserializedFishV1 name=Zed age=10 length=11 weight=12
+ // fishV2 name=Scar age=5 length=12 weight=15 sleeping=true hungry=true angry=true
+ // deserializedFishV2 name=Scar age=5 length=12 weight=15
+```
+
## Class diagram

@@ -25,3 +204,4 @@ Use the Tolerant Reader pattern when
## Credits
* [Martin Fowler - Tolerant Reader](http://martinfowler.com/bliki/TolerantReader.html)
+* [Service Design Patterns: Fundamental Design Solutions for SOAP/WSDL and RESTful Web Services](https://www.amazon.com/gp/product/032154420X/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=032154420X&linkId=94f9516e747ac2b449a959d5b096c73c)
diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java
index 775fc98f7..7529435fe 100644
--- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java
+++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java
@@ -32,10 +32,10 @@ public class RainbowFish implements Serializable {
private static final long serialVersionUID = 1L;
- private String name;
- private int age;
- private int lengthMeters;
- private int weightTons;
+ private final String name;
+ private final int age;
+ private final int lengthMeters;
+ private final int weightTons;
/**
* Constructor.
diff --git a/trampoline/README.md b/trampoline/README.md
index 2356e8715..8831f41e1 100644
--- a/trampoline/README.md
+++ b/trampoline/README.md
@@ -9,14 +9,111 @@ tags:
---
## Intent
-Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack
-and to interleave the execution of functions without hard coding them together
-It is possible by representing a computation in one of 2 states : done | more
-(completed with result, or a reference to the reminder of the computation,
-something like the way a java.util.Supplier does).
+
+Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack and to interleave
+the execution of functions without hard coding them together.
## Explanation
-Trampoline pattern allows to define recursive algorithms by iterative loop.
+
+Recursion is a frequently adopted technique for solving algorithmic problems in a divide and conquer
+style. For example calculating fibonacci accumulating sum and factorials. In these kinds of problems recursion is
+more straightforward than their loop counterpart. Furthermore recursion may need less code and looks more concise.
+There is a saying that every recursion problem can be solved using a loop with the cost of writing code that is more
+difficult to understand.
+
+However recursion type solutions have one big caveat. For each recursive call it typically needs an intermediate value
+stored and there is a limited amount of stack memory available. Running out of stack memory creates a stack overflow
+error and halts the program execution.
+
+Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the stack.
+
+Real world example
+
+> A recursive Fibonacci calculation without the stack overflow problem using the Trampoline pattern.
+
+In plain words
+
+> Trampoline pattern allows recursion without running out of stack memory.
+
+Wikipedia says
+
+> In Java, trampoline refers to using reflection to avoid using inner classes, for example in event listeners. The time overhead of a reflection call is traded for the space overhead of an inner class. Trampolines in Java usually involve the creation of a GenericListener to pass events to an outer class.
+
+**Programmatic Example**
+
+Here's the `Trampoline` implementation in Java.
+
+When `get` is called on the returned Trampoline, internally it will iterate calling `jump` on the returned `Trampoline`
+as long as the concrete instance returned is `Trampoline`, stopping once the returned instance is `done`.
+
+```java
+public interface Trampoline {
+
+ T get();
+
+ default Trampoline