diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java
index 485af25b3..21be23326 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java
index d13021e72..59ca86135 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -27,8 +27,7 @@ import com.iluwatar.abstractdocument.domain.Car;
import com.iluwatar.abstractdocument.domain.enums.Property;
import java.util.List;
import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* The Abstract Document pattern enables handling additional, non-static properties. This pattern
@@ -38,10 +37,9 @@ import org.slf4j.LoggerFactory;
* In Abstract Document pattern,({@link AbstractDocument}) fully implements {@link Document})
* interface. Traits are then defined to enable access to properties in usual, static way.
*/
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
-
/**
* Program entry point.
*
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java
index d0eb85f34..07b1354a3 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java
index bf68d40e5..124890cc5 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java
index 76d7d7431..f1d3f3465 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java
index 54f308ccf..c007072fc 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java
index a50c725c3..2f9318939 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java
index 2722564d5..c1bdc6cf0 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java
index 996598a92..8689c812a 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/enums/Property.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/enums/Property.java
index 640f0ed83..bcd4443cd 100644
--- a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/enums/Property.java
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/enums/Property.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AbstractDocumentTest.java b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AbstractDocumentTest.java
index 13db318e4..c301b85eb 100644
--- a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AbstractDocumentTest.java
+++ b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AbstractDocumentTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,19 +23,18 @@
package com.iluwatar.abstractdocument;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
/**
* AbstractDocument test class
*/
-public class AbstractDocumentTest {
+class AbstractDocumentTest {
private static final String KEY = "key";
private static final String VALUE = "value";
@@ -50,13 +49,13 @@ public class AbstractDocumentTest {
private final DocumentImplementation document = new DocumentImplementation(new HashMap<>());
@Test
- public void shouldPutAndGetValue() {
+ void shouldPutAndGetValue() {
document.put(KEY, VALUE);
assertEquals(VALUE, document.get(KEY));
}
@Test
- public void shouldRetrieveChildren() {
+ void shouldRetrieveChildren() {
var children = List.of(Map.of(), Map.of());
document.put(KEY, children);
@@ -67,14 +66,14 @@ public class AbstractDocumentTest {
}
@Test
- public void shouldRetrieveEmptyStreamForNonExistingChildren() {
+ void shouldRetrieveEmptyStreamForNonExistingChildren() {
var children = document.children(KEY, DocumentImplementation::new);
assertNotNull(children);
assertEquals(0, children.count());
}
@Test
- public void shouldIncludePropsInToString() {
+ void shouldIncludePropsInToString() {
var props = Map.of(KEY, (Object) VALUE);
var document = new DocumentImplementation(props);
assertTrue(document.toString().contains(KEY));
diff --git a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java
index aed63f303..97d730826 100644
--- a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java
+++ b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,14 +25,23 @@ package com.iluwatar.abstractdocument;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Simple App test
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
@Test
- public void shouldExecuteAppWithoutException() {
- App.main(null);
+ void shouldExecuteAppWithoutException() {
+ assertDoesNotThrow(() -> App.main(null));
}
}
diff --git a/abstract-document/src/test/java/com/iluwatar/abstractdocument/DomainTest.java b/abstract-document/src/test/java/com/iluwatar/abstractdocument/DomainTest.java
index 5b1311ff6..a0e129083 100644
--- a/abstract-document/src/test/java/com/iluwatar/abstractdocument/DomainTest.java
+++ b/abstract-document/src/test/java/com/iluwatar/abstractdocument/DomainTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,19 +23,20 @@
package com.iluwatar.abstractdocument;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import com.iluwatar.abstractdocument.domain.Car;
import com.iluwatar.abstractdocument.domain.Part;
import com.iluwatar.abstractdocument.domain.enums.Property;
+import org.junit.jupiter.api.Test;
+
import java.util.List;
import java.util.Map;
-import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Test for Part and Car
*/
-public class DomainTest {
+class DomainTest {
private static final String TEST_PART_TYPE = "test-part-type";
private static final String TEST_PART_MODEL = "test-part-model";
@@ -45,7 +46,7 @@ public class DomainTest {
private static final long TEST_CAR_PRICE = 1L;
@Test
- public void shouldConstructPart() {
+ void shouldConstructPart() {
var partProperties = Map.of(
Property.TYPE.toString(), TEST_PART_TYPE,
Property.MODEL.toString(), TEST_PART_MODEL,
@@ -58,7 +59,7 @@ public class DomainTest {
}
@Test
- public void shouldConstructCar() {
+ void shouldConstructCar() {
var carProperties = Map.of(
Property.MODEL.toString(), TEST_CAR_MODEL,
Property.PRICE.toString(), TEST_CAR_PRICE,
diff --git a/abstract-factory/README.md b/abstract-factory/README.md
index 22edb81e0..4cdbd850a 100644
--- a/abstract-factory/README.md
+++ b/abstract-factory/README.md
@@ -213,8 +213,8 @@ Example use cases
## Related patterns
-[Factory Method](https://java-design-patterns.com/patterns/factory-method/)
-[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
+* [Factory Method](https://java-design-patterns.com/patterns/factory-method/)
+* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
## Credits
diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml
index 614b26232..3b82189b9 100644
--- a/abstract-factory/pom.xml
+++ b/abstract-factory/pom.xml
@@ -1,19 +1,28 @@
-
+
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
abstract-factory
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
index e158ece74..d208002a7 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,9 +23,7 @@
package com.iluwatar.abstractfactory;
-import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that
@@ -41,84 +39,13 @@ import org.slf4j.LoggerFactory;
* and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses
* both concrete implementations to create a king, a castle and an army.
*/
-public class App {
+@Slf4j
+public class App implements Runnable {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+ private final Kingdom kingdom = new Kingdom();
- private King king;
- private Castle castle;
- private Army army;
-
- /**
- * Creates kingdom.
- */
- public void createKingdom(final KingdomFactory factory) {
- setKing(factory.createKing());
- setCastle(factory.createCastle());
- setArmy(factory.createArmy());
- }
-
- King getKing(final KingdomFactory factory) {
- return factory.createKing();
- }
-
- public King getKing() {
- return king;
- }
-
- private void setKing(final King king) {
- this.king = king;
- }
-
- Castle getCastle(final KingdomFactory factory) {
- return factory.createCastle();
- }
-
- public Castle getCastle() {
- return castle;
- }
-
- private void setCastle(final Castle castle) {
- this.castle = castle;
- }
-
- Army getArmy(final KingdomFactory factory) {
- return factory.createArmy();
- }
-
- public Army getArmy() {
- return army;
- }
-
- private void setArmy(final Army army) {
- this.army = army;
- }
-
- /**
- * The factory of kingdom factories.
- */
- public static class FactoryMaker {
-
- /**
- * Enumeration for the different types of Kingdoms.
- */
- public enum KingdomType {
- ELF, ORC
- }
-
- /**
- * The factory method to create KingdomFactory concrete objects.
- */
- public static KingdomFactory makeFactory(KingdomType type) {
- switch (type) {
- case ELF:
- return new ElfKingdomFactory();
- case ORC:
- return new OrcKingdomFactory();
- default:
- throw new IllegalArgumentException("KingdomType not supported.");
- }
- }
+ public Kingdom getKingdom() {
+ return kingdom;
}
/**
@@ -127,19 +54,33 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
-
var app = new App();
+ app.run();
+ }
+ @Override
+ public void run() {
LOGGER.info("Elf Kingdom");
- app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
- LOGGER.info(app.getArmy().getDescription());
- LOGGER.info(app.getCastle().getDescription());
- LOGGER.info(app.getKing().getDescription());
+ createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
+ LOGGER.info(kingdom.getArmy().getDescription());
+ LOGGER.info(kingdom.getCastle().getDescription());
+ LOGGER.info(kingdom.getKing().getDescription());
LOGGER.info("Orc Kingdom");
- app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
- LOGGER.info(app.getArmy().getDescription());
- LOGGER.info(app.getCastle().getDescription());
- LOGGER.info(app.getKing().getDescription());
+ createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
+ LOGGER.info(kingdom.getArmy().getDescription());
+ LOGGER.info(kingdom.getCastle().getDescription());
+ LOGGER.info(kingdom.getKing().getDescription());
+ }
+
+ /**
+ * Creates kingdom.
+ * @param kingdomType type of Kingdom
+ */
+ public void createKingdom(final Kingdom.FactoryMaker.KingdomType kingdomType) {
+ final KingdomFactory kingdomFactory = Kingdom.FactoryMaker.makeFactory(kingdomType);
+ kingdom.setKing(kingdomFactory.createKing());
+ kingdom.setCastle(kingdomFactory.createCastle());
+ kingdom.setArmy(kingdomFactory.createArmy());
}
}
\ No newline at end of file
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java
index 51f69a822..0ed5dd8bd 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java
index c75eb32ef..2977cc978 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java
index 6d2da97cc..ad54943aa 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java
index 5f2b6ed2a..9c2ca1d4b 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java
index f7c4c6146..aa64a489f 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java
index 4493d2d08..a727a1778 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java
index 97e5f676f..704c14679 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java
new file mode 100644
index 000000000..f78e67875
--- /dev/null
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Kingdom.java
@@ -0,0 +1,63 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.abstractfactory;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class Kingdom {
+
+ private King king;
+ private Castle castle;
+ private Army army;
+
+ /**
+ * The factory of kingdom factories.
+ */
+ public static class FactoryMaker {
+
+ /**
+ * Enumeration for the different types of Kingdoms.
+ */
+ public enum KingdomType {
+ ELF, ORC
+ }
+
+ /**
+ * The factory method to create KingdomFactory concrete objects.
+ */
+ public static KingdomFactory makeFactory(KingdomType type) {
+ switch (type) {
+ case ELF:
+ return new ElfKingdomFactory();
+ case ORC:
+ return new OrcKingdomFactory();
+ default:
+ throw new IllegalArgumentException("KingdomType not supported.");
+ }
+ }
+ }
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java
index a72dbf78c..520e36de0 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java
index ae0bd5c3e..fa7bf3889 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java
index 458a61bf9..fea7c1866 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java
index f73ada9b0..9a47a9d0b 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java
index ae7c744be..eb038ca61 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
index f3db525a1..3136ee29f 100644
--- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
+++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,65 +23,71 @@
package com.iluwatar.abstractfactory;
+import org.junit.jupiter.api.Test;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import com.iluwatar.abstractfactory.App.FactoryMaker;
-import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
/**
* Test for abstract factory.
*/
-public class AbstractFactoryTest {
+class AbstractFactoryTest {
private final App app = new App();
- private KingdomFactory elfFactory;
- private KingdomFactory orcFactory;
-
- @BeforeEach
- public void setUp() {
- elfFactory = FactoryMaker.makeFactory(KingdomType.ELF);
- orcFactory = FactoryMaker.makeFactory(KingdomType.ORC);
- }
@Test
- public void king() {
- final var elfKing = app.getKing(elfFactory);
+ void king() {
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
+ final var kingdom = app.getKingdom();
+
+ final var elfKing = kingdom.getKing();
assertTrue(elfKing instanceof ElfKing);
assertEquals(ElfKing.DESCRIPTION, elfKing.getDescription());
- final var orcKing = app.getKing(orcFactory);
+
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
+ final var orcKing = kingdom.getKing();
assertTrue(orcKing instanceof OrcKing);
assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription());
}
@Test
- public void castle() {
- final var elfCastle = app.getCastle(elfFactory);
+ void castle() {
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
+ final var kingdom = app.getKingdom();
+
+ final var elfCastle = kingdom.getCastle();
assertTrue(elfCastle instanceof ElfCastle);
assertEquals(ElfCastle.DESCRIPTION, elfCastle.getDescription());
- final var orcCastle = app.getCastle(orcFactory);
+
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
+ final var orcCastle = kingdom.getCastle();
assertTrue(orcCastle instanceof OrcCastle);
assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription());
}
@Test
- public void army() {
- final var elfArmy = app.getArmy(elfFactory);
+ void army() {
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
+ final var kingdom = app.getKingdom();
+
+ final var elfArmy = kingdom.getArmy();
assertTrue(elfArmy instanceof ElfArmy);
assertEquals(ElfArmy.DESCRIPTION, elfArmy.getDescription());
- final var orcArmy = app.getArmy(orcFactory);
+
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
+ final var orcArmy = kingdom.getArmy();
assertTrue(orcArmy instanceof OrcArmy);
assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription());
}
@Test
- public void createElfKingdom() {
- app.createKingdom(elfFactory);
- final var king = app.getKing();
- final var castle = app.getCastle();
- final var army = app.getArmy();
+ void createElfKingdom() {
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
+ final var kingdom = app.getKingdom();
+
+ final var king = kingdom.getKing();
+ final var castle = kingdom.getCastle();
+ final var army = kingdom.getArmy();
assertTrue(king instanceof ElfKing);
assertEquals(ElfKing.DESCRIPTION, king.getDescription());
assertTrue(castle instanceof ElfCastle);
@@ -91,11 +97,13 @@ public class AbstractFactoryTest {
}
@Test
- public void createOrcKingdom() {
- app.createKingdom(orcFactory);
- final var king = app.getKing();
- final var castle = app.getCastle();
- final var army = app.getArmy();
+ void createOrcKingdom() {
+ app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
+ final var kingdom = app.getKingdom();
+
+ final var king = kingdom.getKing();
+ final var castle = kingdom.getCastle();
+ final var army = kingdom.getArmy();
assertTrue(king instanceof OrcKing);
assertEquals(OrcKing.DESCRIPTION, king.getDescription());
assertTrue(castle instanceof OrcCastle);
diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java
index 4036cc9b8..c5589895d 100644
--- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java
+++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,12 +25,19 @@ package com.iluwatar.abstractfactory;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
- * Tests that Abstract Factory example runs without errors.
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
*/
-public class AppTest {
+class AppTest {
+
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/active-object/README.md b/active-object/README.md
new file mode 100644
index 000000000..6e26a8595
--- /dev/null
+++ b/active-object/README.md
@@ -0,0 +1,125 @@
+---
+layout: pattern
+title: Active Object
+folder: active-object
+permalink: /patterns/active-object/
+categories: Concurrency
+tags:
+ - Performance
+---
+
+
+## Intent
+The active object design pattern decouples method execution from method invocation for objects that each reside in their thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests.
+
+## Explanation
+
+The class that implements the active object pattern will contain a self-synchronization mechanism without using 'synchronized' methods.
+
+Real-world example
+
+>The Orcs are known for their wildness and untameable soul. It seems like they have their own thread of control based on previous behavior.
+
+To implement a creature that has its own thread of control mechanism and expose its API only and not the execution itself, we can use the Active Object pattern.
+
+
+**Programmatic Example**
+
+```java
+public abstract class ActiveCreature{
+ private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());
+
+ private BlockingQueue requests;
+
+ private String name;
+
+ private Thread thread;
+
+ public ActiveCreature(String name) {
+ this.name = name;
+ this.requests = new LinkedBlockingQueue();
+ thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ requests.take().run();
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ }
+ }
+ }
+ }
+ );
+ thread.start();
+ }
+
+ public void eat() throws InterruptedException {
+ requests.put(new Runnable() {
+ @Override
+ public void run() {
+ logger.info("{} is eating!",name());
+ logger.info("{} has finished eating!",name());
+ }
+ }
+ );
+ }
+
+ public void roam() throws InterruptedException {
+ requests.put(new Runnable() {
+ @Override
+ public void run() {
+ logger.info("{} has started to roam and the wastelands.",name());
+ }
+ }
+ );
+ }
+
+ public String name() {
+ return this.name;
+ }
+}
+```
+
+We can see that any class that will extend the ActiveCreature class will have its own thread of control to execute and invocate methods.
+
+For example, the Orc class:
+
+```java
+public class Orc extends ActiveCreature {
+
+ public Orc(String name) {
+ super(name);
+ }
+
+}
+```
+
+Now, we can create multiple creatures such as Orcs, tell them to eat and roam and they will execute it on their own thread of control:
+
+```java
+ public static void main(String[] args) {
+ var app = new App();
+ app.run();
+ }
+
+ @Override
+ public void run() {
+ ActiveCreature creature;
+ try {
+ for (int i = 0;i < creatures;i++) {
+ creature = new Orc(Orc.class.getSimpleName().toString() + i);
+ creature.eat();
+ creature.roam();
+ }
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ }
+ Runtime.getRuntime().exit(1);
+ }
+```
+
+## Class diagram
+
+
diff --git a/active-object/etc/active-object.urm.PNG b/active-object/etc/active-object.urm.PNG
new file mode 100644
index 000000000..c14f66144
Binary files /dev/null and b/active-object/etc/active-object.urm.PNG differ
diff --git a/active-object/etc/active-object.urm.puml b/active-object/etc/active-object.urm.puml
new file mode 100644
index 000000000..3fc3c8e1e
--- /dev/null
+++ b/active-object/etc/active-object.urm.puml
@@ -0,0 +1,25 @@
+@startuml
+package com.iluwatar.activeobject {
+ abstract class ActiveCreature {
+ - logger : Logger
+ - name : String
+ - requests : BlockingQueue
+ - thread : Thread
+ + ActiveCreature(name : String)
+ + eat()
+ + name() : String
+ + roam()
+ }
+ class App {
+ - creatures : Integer
+ - logger : Logger
+ + App()
+ + main(args : String[]) {static}
+ + run()
+ }
+ class Orc {
+ + Orc(name : String)
+ }
+}
+Orc --|> ActiveCreature
+@enduml
\ No newline at end of file
diff --git a/active-object/pom.xml b/active-object/pom.xml
new file mode 100644
index 000000000..3ea22d4e2
--- /dev/null
+++ b/active-object/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.24.0-SNAPSHOT
+
+ active-object
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.activeobject.App
+
+
+
+
+
+
+
+
+
diff --git a/active-object/src/main/java/com/iluwatar/activeobject/ActiveCreature.java b/active-object/src/main/java/com/iluwatar/activeobject/ActiveCreature.java
new file mode 100644
index 000000000..479dc0643
--- /dev/null
+++ b/active-object/src/main/java/com/iluwatar/activeobject/ActiveCreature.java
@@ -0,0 +1,118 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.activeobject;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ActiveCreature class is the base of the active object example.
+ * @author Noam Greenshtain
+ *
+ */
+public abstract class ActiveCreature {
+
+ private static final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());
+
+ private BlockingQueue requests;
+
+ private String name;
+
+ private Thread thread; // Thread of execution.
+
+ private int status; // status of the thread of execution.
+
+ /**
+ * Constructor and initialization.
+ */
+ protected ActiveCreature(String name) {
+ this.name = name;
+ this.status = 0;
+ this.requests = new LinkedBlockingQueue<>();
+ thread = new Thread(() -> {
+ boolean infinite = true;
+ while (infinite) {
+ try {
+ requests.take().run();
+ } catch (InterruptedException e) {
+ if (this.status != 0) {
+ logger.error("Thread was interrupted. --> {}", e.getMessage());
+ }
+ infinite = false;
+ Thread.currentThread().interrupt();
+ }
+ }
+ });
+ thread.start();
+ }
+
+ /**
+ * Eats the porridge.
+ * @throws InterruptedException due to firing a new Runnable.
+ */
+ public void eat() throws InterruptedException {
+ requests.put(() -> {
+ logger.info("{} is eating!",name());
+ logger.info("{} has finished eating!",name());
+ });
+ }
+
+ /**
+ * Roam in the wastelands.
+ * @throws InterruptedException due to firing a new Runnable.
+ */
+ public void roam() throws InterruptedException {
+ requests.put(() ->
+ logger.info("{} has started to roam in the wastelands.",name())
+ );
+ }
+
+ /**
+ * Returns the name of the creature.
+ * @return the name of the creature.
+ */
+ public String name() {
+ return this.name;
+ }
+
+ /**
+ * Kills the thread of execution.
+ * @param status of the thread of execution. 0 == OK, the rest is logging an error.
+ */
+ public void kill(int status) {
+ this.status = status;
+ this.thread.interrupt();
+ }
+
+ /**
+ * Returns the status of the thread of execution.
+ * @return the status of the thread of execution.
+ */
+ public int getStatus() {
+ return this.status;
+ }
+}
diff --git a/active-object/src/main/java/com/iluwatar/activeobject/App.java b/active-object/src/main/java/com/iluwatar/activeobject/App.java
new file mode 100644
index 000000000..d36d1023d
--- /dev/null
+++ b/active-object/src/main/java/com/iluwatar/activeobject/App.java
@@ -0,0 +1,75 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.activeobject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Active Object pattern helps to solve synchronization difficulties without using
+ * 'synchronized' methods. The active object will contain a thread-safe data structure
+ * (such as BlockingQueue) and use to synchronize method calls by moving the logic of the method
+ * into an invocator(usually a Runnable) and store it in the DSA.
+ *
+ * In this example, we fire 20 threads to modify a value in the target class.
+ */
+public class App implements Runnable {
+
+ private static final Logger logger = LoggerFactory.getLogger(App.class.getName());
+
+ private static final int NUM_CREATURES = 3;
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line arguments.
+ */
+ public static void main(String[] args) {
+ var app = new App();
+ app.run();
+ }
+
+ @Override
+ public void run() {
+ List creatures = new ArrayList<>();
+ try {
+ for (int i = 0;i < NUM_CREATURES;i++) {
+ creatures.add(new Orc(Orc.class.getSimpleName() + i));
+ creatures.get(i).eat();
+ creatures.get(i).roam();
+ }
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ Thread.currentThread().interrupt();
+ } finally {
+ for (int i = 0;i < NUM_CREATURES;i++) {
+ creatures.get(i).kill(0);
+ }
+ }
+ }
+}
diff --git a/command/src/main/java/com/iluwatar/command/Command.java b/active-object/src/main/java/com/iluwatar/activeobject/Orc.java
similarity index 81%
rename from command/src/main/java/com/iluwatar/command/Command.java
rename to active-object/src/main/java/com/iluwatar/activeobject/Orc.java
index 83010f160..2bce5b2b0 100644
--- a/command/src/main/java/com/iluwatar/command/Command.java
+++ b/active-object/src/main/java/com/iluwatar/activeobject/Orc.java
@@ -1,37 +1,37 @@
-/*
- * 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.command;
-
-/**
- * Interface for Commands.
- */
-public interface Command {
- void execute(Target target);
-
- void undo();
-
- void redo();
-
- String toString();
-}
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.activeobject;
+
+/**
+ * An implementation of the ActiveCreature class.
+ * @author Noam Greenshtain
+ *
+ */
+public class Orc extends ActiveCreature {
+
+ public Orc(String name) {
+ super(name);
+ }
+
+}
diff --git a/circuit-breaker/src/test/java/com/iluwatar/circuitbreaker/DelayedServiceTest.java b/active-object/src/test/java/com/iluwatar/activeobject/ActiveCreatureTest.java
similarity index 77%
rename from circuit-breaker/src/test/java/com/iluwatar/circuitbreaker/DelayedServiceTest.java
rename to active-object/src/test/java/com/iluwatar/activeobject/ActiveCreatureTest.java
index af747f794..8a4296a1f 100644
--- a/circuit-breaker/src/test/java/com/iluwatar/circuitbreaker/DelayedServiceTest.java
+++ b/active-object/src/test/java/com/iluwatar/activeobject/ActiveCreatureTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,21 +21,22 @@
* THE SOFTWARE.
*/
-package com.iluwatar.circuitbreaker;
+package com.iluwatar.activeobject;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
+class ActiveCreatureTest {
+
+ @Test
+ void executionTest() throws InterruptedException {
+ ActiveCreature orc = new Orc("orc1");
+ assertEquals("orc1",orc.name());
+ assertEquals(0,orc.getStatus());
+ orc.eat();
+ orc.roam();
+ orc.kill(0);
+ }
+
-/**
- * Monitoring Service test
- */
-public class DelayedServiceTest {
-
- //Improves code coverage
- @Test
- public void testDefaultConstructor() {
- var obj = new DelayedService();
- assertEquals(obj.response(System.nanoTime()), "Delayed service is down");
- }
}
diff --git a/active-object/src/test/java/com/iluwatar/activeobject/AppTest.java b/active-object/src/test/java/com/iluwatar/activeobject/AppTest.java
new file mode 100644
index 000000000..c7b223d67
--- /dev/null
+++ b/active-object/src/test/java/com/iluwatar/activeobject/AppTest.java
@@ -0,0 +1,37 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.activeobject;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import org.junit.jupiter.api.Test;
+
+
+class AppTest {
+
+ @Test
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
+ }
+}
diff --git a/acyclic-visitor/pom.xml b/acyclic-visitor/pom.xml
index 24bab933a..234cbfefc 100644
--- a/acyclic-visitor/pom.xml
+++ b/acyclic-visitor/pom.xml
@@ -1,18 +1,27 @@
-
+
@@ -21,7 +30,7 @@
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
acyclic-visitor
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/AllModemVisitor.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/AllModemVisitor.java
index 354c4db74..28345c505 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/AllModemVisitor.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/AllModemVisitor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/App.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/App.java
index 866abc3b7..b151019c2 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/App.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitor.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitor.java
index f9df38529..bfe7f6646 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitor.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,17 +23,15 @@
package com.iluwatar.acyclicvisitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* ConfigureForDosVisitor class implements both zoom's and hayes' visit method for Dos
* manufacturer.
*/
+@Slf4j
public class ConfigureForDosVisitor implements AllModemVisitor {
- private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
-
@Override
public void visit(Hayes hayes) {
LOGGER.info(hayes + " used with Dos configurator.");
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitor.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitor.java
index 3d14eff8f..1f465967f 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitor.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,17 +23,15 @@
package com.iluwatar.acyclicvisitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* ConfigureForUnixVisitor class implements zoom's visit method for Unix manufacturer, unlike
* traditional visitor pattern, this class may selectively implement visit for other modems.
*/
+@Slf4j
public class ConfigureForUnixVisitor implements ZoomVisitor {
- private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForUnixVisitor.class);
-
@Override
public void visit(Zoom zoom) {
LOGGER.info(zoom + " used with Unix configurator.");
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Hayes.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Hayes.java
index b49a6234c..3e30258f5 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Hayes.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Hayes.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,16 +23,14 @@
package com.iluwatar.acyclicvisitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* Hayes class implements its accept method.
*/
+@Slf4j
public class Hayes extends Modem {
- private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
-
/**
* Accepts all visitors but honors only HayesVisitor.
*/
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/HayesVisitor.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/HayesVisitor.java
index 59527d57b..06ee5300d 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/HayesVisitor.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/HayesVisitor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Modem.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Modem.java
index 201712dd1..04018d543 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Modem.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Modem.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ModemVisitor.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ModemVisitor.java
index b4058f237..b2181fe7c 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ModemVisitor.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ModemVisitor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Zoom.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Zoom.java
index 3fbaa38df..01e7e7aca 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Zoom.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/Zoom.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,16 +23,14 @@
package com.iluwatar.acyclicvisitor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* Zoom class implements its accept method.
*/
+@Slf4j
public class Zoom extends Modem {
- private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
-
/**
* Accepts all visitors but honors only ZoomVisitor.
*/
diff --git a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ZoomVisitor.java b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ZoomVisitor.java
index fd54d8b21..e86a64fa6 100644
--- a/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ZoomVisitor.java
+++ b/acyclic-visitor/src/main/java/com/iluwatar/acyclicvisitor/ZoomVisitor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java
index 4b9a7ec6c..12f0ba6ce 100644
--- a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java
+++ b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,13 +25,23 @@ package com.iluwatar.acyclicvisitor;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that the Acyclic Visitor example runs without errors.
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
\ No newline at end of file
diff --git a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java
index 79097a454..b41fc956c 100644
--- a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java
+++ b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForDosVisitorTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -35,34 +35,34 @@ import uk.org.lidalia.slf4jtest.TestLoggerFactory;
/**
* ConfigureForDosVisitor test class
*/
-public class ConfigureForDosVisitorTest {
+class ConfigureForDosVisitorTest {
private final TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
-
+
@Test
- public void testVisitForZoom() {
+ void testVisitForZoom() {
var conDos = new ConfigureForDosVisitor();
var zoom = new Zoom();
-
+
conDos.visit(zoom);
-
+
assertThat(logger.getLoggingEvents())
.extracting("level", "message")
.contains(tuple(INFO, zoom + " used with Dos configurator."));
}
-
+
@Test
- public void testVisitForHayes() {
+ void testVisitForHayes() {
var conDos = new ConfigureForDosVisitor();
var hayes = new Hayes();
-
+
conDos.visit(hayes);
-
+
assertThat(logger.getLoggingEvents())
.extracting("level", "message")
.contains(tuple(INFO, hayes + " used with Dos configurator."));
}
-
+
@AfterEach
public void clearLoggers() {
TestLoggerFactory.clear();
diff --git a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitorTest.java b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitorTest.java
index 32067ad38..d2ea55809 100644
--- a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitorTest.java
+++ b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ConfigureForUnixVisitorTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,35 +23,34 @@
package com.iluwatar.acyclicvisitor;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import uk.org.lidalia.slf4jtest.TestLogger;
+import uk.org.lidalia.slf4jtest.TestLoggerFactory;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.groups.Tuple.tuple;
import static uk.org.lidalia.slf4jext.Level.INFO;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Test;
-
-import uk.org.lidalia.slf4jtest.TestLogger;
-import uk.org.lidalia.slf4jtest.TestLoggerFactory;
-
/**
* ConfigureForUnixVisitor test class
*/
-public class ConfigureForUnixVisitorTest {
-
+class ConfigureForUnixVisitorTest {
+
private static final TestLogger LOGGER = TestLoggerFactory.getTestLogger(ConfigureForUnixVisitor.class);
-
+
@AfterEach
public void clearLoggers() {
TestLoggerFactory.clear();
}
-
+
@Test
- public void testVisitForZoom() {
+ void testVisitForZoom() {
var conUnix = new ConfigureForUnixVisitor();
var zoom = new Zoom();
-
+
conUnix.visit(zoom);
-
+
assertThat(LOGGER.getLoggingEvents())
.extracting("level", "message")
.contains(tuple(INFO, zoom + " used with Unix configurator."));
diff --git a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/HayesTest.java b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/HayesTest.java
index 308dd5879..eaf9fb152 100644
--- a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/HayesTest.java
+++ b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/HayesTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,34 +23,32 @@
package com.iluwatar.acyclicvisitor;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
import org.junit.jupiter.api.Test;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
/**
* Hayes test class
*/
-public class HayesTest {
+class HayesTest {
@Test
- public void testAcceptForDos() {
+ void testAcceptForDos() {
var hayes = new Hayes();
var mockVisitor = mock(ConfigureForDosVisitor.class);
-
+
hayes.accept(mockVisitor);
- verify((HayesVisitor)mockVisitor).visit(eq(hayes));
+ verify((HayesVisitor) mockVisitor).visit(eq(hayes));
}
-
+
@Test
- public void testAcceptForUnix() {
+ void testAcceptForUnix() {
var hayes = new Hayes();
var mockVisitor = mock(ConfigureForUnixVisitor.class);
-
+
hayes.accept(mockVisitor);
-
+
verifyZeroInteractions(mockVisitor);
}
}
diff --git a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ZoomTest.java b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ZoomTest.java
index 2dcfcfbbb..4373fe818 100644
--- a/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ZoomTest.java
+++ b/acyclic-visitor/src/test/java/com/iluwatar/acyclicvisitor/ZoomTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,32 +24,32 @@
package com.iluwatar.acyclicvisitor;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.mock;
-
import org.junit.jupiter.api.Test;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
/**
* Zoom test class
*/
-public class ZoomTest {
-
+class ZoomTest {
+
@Test
- public void testAcceptForDos() {
+ void testAcceptForDos() {
var zoom = new Zoom();
var mockVisitor = mock(ConfigureForDosVisitor.class);
-
+
zoom.accept(mockVisitor);
- verify((ZoomVisitor)mockVisitor).visit(eq(zoom));
+ verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
}
-
+
@Test
- public void testAcceptForUnix() {
+ void testAcceptForUnix() {
var zoom = new Zoom();
var mockVisitor = mock(ConfigureForUnixVisitor.class);
-
+
zoom.accept(mockVisitor);
- verify((ZoomVisitor)mockVisitor).visit(eq(zoom));
+ verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
}
}
diff --git a/adapter/README.md b/adapter/README.md
index aef4cdb69..65ffa4fc6 100644
--- a/adapter/README.md
+++ b/adapter/README.md
@@ -42,8 +42,8 @@ public interface RowingBoat {
void row();
}
+@Slf4j
public class FishingBoat {
- private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);
public void sail() {
LOGGER.info("The fishing boat is sailing");
}
@@ -70,10 +70,9 @@ public class Captain {
Now let's say the pirates are coming and our captain needs to escape but there is only fishing boat available. We need to create an adapter that allows the captain to operate the fishing boat with his rowing boat skills.
```java
+@Slf4j
public class FishingBoatAdapter implements RowingBoat {
- private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
-
private final FishingBoat boat;
public FishingBoatAdapter() {
diff --git a/adapter/pom.xml b/adapter/pom.xml
index 4c725def8..f50a7ae3d 100644
--- a/adapter/pom.xml
+++ b/adapter/pom.xml
@@ -1,19 +1,28 @@
-
+
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
adapter
diff --git a/adapter/src/main/java/com/iluwatar/adapter/App.java b/adapter/src/main/java/com/iluwatar/adapter/App.java
index 4e3755fb2..1375d85c7 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/App.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/adapter/src/main/java/com/iluwatar/adapter/Captain.java b/adapter/src/main/java/com/iluwatar/adapter/Captain.java
index b83b13429..036792e8c 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/Captain.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/Captain.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,24 +23,20 @@
package com.iluwatar.adapter;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
/**
* The Captain uses {@link RowingBoat} to sail. This is the client in the pattern.
*/
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
public final class Captain {
private RowingBoat rowingBoat;
- public Captain() {
- }
-
- public Captain(final RowingBoat boat) {
- this.rowingBoat = boat;
- }
-
- void setRowingBoat(final RowingBoat boat) {
- this.rowingBoat = boat;
- }
-
void row() {
rowingBoat.row();
}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java
index 123006c46..38866dc33 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,18 +23,15 @@
package com.iluwatar.adapter;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import org.slf4j.Logger;
+import lombok.extern.slf4j.Slf4j;
/**
* Device class (adaptee in the pattern). We want to reuse this class. Fishing boat moves by
* sailing.
*/
+@Slf4j
final class FishingBoat {
- private static final Logger LOGGER = getLogger(FishingBoat.class);
-
void sail() {
LOGGER.info("The fishing boat is sailing");
}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java
index 39a9adab4..73c7dd60e 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoatAdapter.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -29,11 +29,7 @@ package com.iluwatar.adapter;
*/
public class FishingBoatAdapter implements RowingBoat {
- private final FishingBoat boat;
-
- public FishingBoatAdapter() {
- boat = new FishingBoat();
- }
+ private final FishingBoat boat = new FishingBoat();
public final void row() {
boat.sail();
diff --git a/adapter/src/main/java/com/iluwatar/adapter/RowingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/RowingBoat.java
index 908036a3f..69d39c193 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/RowingBoat.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/RowingBoat.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/adapter/src/main/java/com/iluwatar/adapter/package-info.java b/adapter/src/main/java/com/iluwatar/adapter/package-info.java
index d036d86dd..873df29c5 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/package-info.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/package-info.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
index f87073b23..fc55cd69e 100644
--- a/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
+++ b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,18 +23,19 @@
package com.iluwatar.adapter;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
/**
* Test class
*/
-public class AdapterPatternTest {
+class AdapterPatternTest {
private Map beans;
@@ -64,7 +65,7 @@ public class AdapterPatternTest {
* by the client ({@link Captain} ).
*/
@Test
- public void testAdapter() {
+ void testAdapter() {
var captain = (Captain) beans.get(ROWING_BEAN);
// when captain moves
diff --git a/adapter/src/test/java/com/iluwatar/adapter/AppTest.java b/adapter/src/test/java/com/iluwatar/adapter/AppTest.java
index 3bf8e1010..8b224e451 100644
--- a/adapter/src/test/java/com/iluwatar/adapter/AppTest.java
+++ b/adapter/src/test/java/com/iluwatar/adapter/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,12 +25,23 @@ package com.iluwatar.adapter;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that Adapter example runs without errors.
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml
index f4482d0e3..46337c0ec 100644
--- a/aggregator-microservices/aggregator-service/pom.xml
+++ b/aggregator-microservices/aggregator-service/pom.xml
@@ -1,26 +1,35 @@
-
+
aggregator-microservices
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
4.0.0
aggregator-service
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Aggregator.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Aggregator.java
index f28377a1d..209187bd7 100644
--- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Aggregator.java
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Aggregator.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -26,8 +26,7 @@ package com.iluwatar.aggregator.microservices;
import static java.util.Objects.requireNonNullElse;
import javax.annotation.Resource;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
@@ -37,20 +36,18 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class Aggregator {
-
@Resource
private ProductInformationClient informationClient;
@Resource
private ProductInventoryClient inventoryClient;
-
/**
* Retrieves product data.
*
* @return a Product.
*/
- @RequestMapping(path = "/product", method = RequestMethod.GET)
+ @GetMapping("/product")
public Product getProduct() {
var product = new Product();
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java
index 3c09c54be..791df87ba 100644
--- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Product.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Product.java
index 3c214a58a..f451728b9 100644
--- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Product.java
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Product.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,9 +23,14 @@
package com.iluwatar.aggregator.microservices;
+import lombok.Getter;
+import lombok.Setter;
+
/**
* Encapsulates all the data for a Product that clients will request.
*/
+@Getter
+@Setter
public class Product {
/**
@@ -39,20 +44,4 @@ public class Product {
*/
private int productInventories;
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public int getProductInventories() {
- return productInventories;
- }
-
- public void setProductInventories(int productInventories) {
- this.productInventories = productInventories;
- }
-
}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClient.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClient.java
index 47d786ec6..75d87967d 100644
--- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClient.java
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClient.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java
index d19dcd829..2fcad382e 100644
--- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -28,18 +28,16 @@ import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* An adapter to communicate with information micro-service.
*/
+@Slf4j
@Component
public class ProductInformationClientImpl implements ProductInformationClient {
- private static final Logger LOGGER = LoggerFactory.getLogger(ProductInformationClientImpl.class);
-
@Override
public String getProductTitle() {
var request = HttpRequest.newBuilder()
@@ -54,6 +52,7 @@ public class ProductInformationClientImpl implements ProductInformationClient {
LOGGER.error("IOException Occurred", ioe);
} catch (InterruptedException ie) {
LOGGER.error("InterruptedException Occurred", ie);
+ Thread.currentThread().interrupt();
}
return null;
}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClient.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClient.java
index 22369350a..1ddba57ba 100644
--- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClient.java
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClient.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java
index e493c8040..cc78d2d8d 100644
--- a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -28,18 +28,16 @@ import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* An adapter to communicate with inventory micro-service.
*/
+@Slf4j
@Component
public class ProductInventoryClientImpl implements ProductInventoryClient {
- private static final Logger LOGGER = LoggerFactory.getLogger(ProductInventoryClientImpl.class);
-
@Override
public Integer getProductInventories() {
var response = "";
@@ -56,6 +54,7 @@ public class ProductInventoryClientImpl implements ProductInventoryClient {
LOGGER.error("IOException Occurred", ioe);
} catch (InterruptedException ie) {
LOGGER.error("InterruptedException Occurred", ie);
+ Thread.currentThread().interrupt();
}
if ("".equalsIgnoreCase(response)) {
return null;
diff --git a/aggregator-microservices/aggregator-service/src/main/resources/application.properties b/aggregator-microservices/aggregator-service/src/main/resources/application.properties
index f9e29f5a7..79c2622b2 100644
--- a/aggregator-microservices/aggregator-service/src/main/resources/application.properties
+++ b/aggregator-microservices/aggregator-service/src/main/resources/application.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
@@ -20,4 +20,5 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
+
server.port=50004
\ No newline at end of file
diff --git a/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java
index cb958ecf9..2ffa9cd42 100644
--- a/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java
+++ b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,19 +23,19 @@
package com.iluwatar.aggregator.microservices;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.when;
-
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.when;
+
/**
* Test Aggregation of domain objects
*/
-public class AggregatorTest {
+class AggregatorTest {
@InjectMocks
private Aggregator aggregator;
@@ -55,7 +55,7 @@ public class AggregatorTest {
* Tests getting the data for a desktop client
*/
@Test
- public void testGetProduct() {
+ void testGetProduct() {
var title = "The Product Title.";
var inventories = 5;
diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml
index f99d26b65..43d5ba072 100644
--- a/aggregator-microservices/information-microservice/pom.xml
+++ b/aggregator-microservices/information-microservice/pom.xml
@@ -1,26 +1,35 @@
-
+
aggregator-microservices
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
4.0.0
diff --git a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationApplication.java b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationApplication.java
index 3815fffc4..0db963733 100644
--- a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationApplication.java
+++ b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationApplication.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java
index 2accc013d..4849e4228 100644
--- a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java
+++ b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,8 +23,7 @@
package com.iluwatar.information.microservice;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
@@ -38,7 +37,7 @@ public class InformationController {
*
* @return product inventory.
*/
- @RequestMapping(value = "/information", method = RequestMethod.GET)
+ @GetMapping("/information")
public String getProductTitle() {
return "The Product Title.";
}
diff --git a/aggregator-microservices/information-microservice/src/main/resources/application.properties b/aggregator-microservices/information-microservice/src/main/resources/application.properties
index b953a61da..8f2a5f174 100644
--- a/aggregator-microservices/information-microservice/src/main/resources/application.properties
+++ b/aggregator-microservices/information-microservice/src/main/resources/application.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
@@ -20,4 +20,5 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
+
server.port=51515
\ No newline at end of file
diff --git a/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java b/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java
index 90388af1a..909392d1d 100644
--- a/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java
+++ b/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,17 +23,17 @@
package com.iluwatar.information.microservice;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
/**
* Test for Information Rest Controller
*/
-public class InformationControllerTest {
+class InformationControllerTest {
@Test
- public void shouldGetProductTitle() {
+ void shouldGetProductTitle() {
var infoController = new InformationController();
var title = infoController.getProductTitle();
assertEquals("The Product Title.", title);
diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml
index f7899aa8f..9f74cf7c9 100644
--- a/aggregator-microservices/inventory-microservice/pom.xml
+++ b/aggregator-microservices/inventory-microservice/pom.xml
@@ -1,26 +1,35 @@
-
+
aggregator-microservices
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
4.0.0
inventory-microservice
diff --git a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryApplication.java b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryApplication.java
index 9a49518b5..a97b609ac 100644
--- a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryApplication.java
+++ b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryApplication.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java
index e3c3838f8..0e40507cc 100644
--- a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java
+++ b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,8 +23,7 @@
package com.iluwatar.inventory.microservice;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
@@ -38,7 +37,7 @@ public class InventoryController {
*
* @return product inventory.
*/
- @RequestMapping(value = "/inventories", method = RequestMethod.GET)
+ @GetMapping("/inventories")
public int getProductInventories() {
return 5;
}
diff --git a/aggregator-microservices/inventory-microservice/src/main/resources/application.properties b/aggregator-microservices/inventory-microservice/src/main/resources/application.properties
index 9d2021f44..380791d88 100644
--- a/aggregator-microservices/inventory-microservice/src/main/resources/application.properties
+++ b/aggregator-microservices/inventory-microservice/src/main/resources/application.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
@@ -20,4 +20,5 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
+
server.port=51516
\ No newline at end of file
diff --git a/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java b/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java
index e9961796b..9a85f1d5a 100644
--- a/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java
+++ b/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,16 +23,17 @@
package com.iluwatar.inventory.microservice;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
/**
* Test Inventory Rest Controller
*/
-public class InventoryControllerTest {
+class InventoryControllerTest {
+
@Test
- public void testGetProductInventories() {
+ void testGetProductInventories() {
var inventoryController = new InventoryController();
var numberOfInventories = inventoryController.getProductInventories();
assertEquals(5, numberOfInventories);
diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml
index a63ec2f12..f5d18c2b4 100644
--- a/aggregator-microservices/pom.xml
+++ b/aggregator-microservices/pom.xml
@@ -2,7 +2,7 @@
+
java-design-patterns
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
4.0.0
ambassador
diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/App.java b/ambassador/src/main/java/com/iluwatar/ambassador/App.java
index 087fc39c0..6da5a2588 100644
--- a/ambassador/src/main/java/com/iluwatar/ambassador/App.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java
index 70d52e799..0ec258016 100644
--- a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,20 +23,19 @@
package com.iluwatar.ambassador;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* A simple Client.
*/
+@Slf4j
public class Client {
- private static final Logger LOGGER = LoggerFactory.getLogger(Client.class);
private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador();
long useService(int value) {
var result = serviceAmbassador.doRemoteFunction(value);
- LOGGER.info("Service result: " + result);
+ LOGGER.info("Service result: {}", result);
return result;
}
}
diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java
index a80806851..18a2d2214 100644
--- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -26,15 +26,14 @@ package com.iluwatar.ambassador;
import static java.lang.Thread.sleep;
import com.iluwatar.ambassador.util.RandomProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* A remote legacy application represented by a Singleton implementation.
*/
+@Slf4j
public class RemoteService implements RemoteServiceInterface {
private static final int THRESHOLD = 200;
- private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
private static RemoteService service = null;
private final RandomProvider randomProvider;
@@ -62,7 +61,7 @@ public class RemoteService implements RemoteServiceInterface {
*
* @param value integer value to be multiplied.
* @return if waitTime is less than {@link RemoteService#THRESHOLD}, it returns value * 10,
- * otherwise {@link RemoteServiceInterface#FAILURE}.
+ * otherwise {@link RemoteServiceStatus#FAILURE}.
*/
@Override
public long doRemoteFunction(int value) {
@@ -73,7 +72,9 @@ public class RemoteService implements RemoteServiceInterface {
sleep(waitTime);
} catch (InterruptedException e) {
LOGGER.error("Thread sleep state interrupted", e);
+ Thread.currentThread().interrupt();
}
- return waitTime <= THRESHOLD ? value * 10 : FAILURE;
+ return waitTime <= THRESHOLD ? value * 10
+ : RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue();
}
}
diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java
index 5b4995134..3012eea29 100644
--- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -27,7 +27,6 @@ package com.iluwatar.ambassador;
* Interface shared by ({@link RemoteService}) and ({@link ServiceAmbassador}).
*/
interface RemoteServiceInterface {
- int FAILURE = -1;
long doRemoteFunction(int value);
}
diff --git a/command/src/main/java/com/iluwatar/command/InvisibilitySpell.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java
similarity index 63%
rename from command/src/main/java/com/iluwatar/command/InvisibilitySpell.java
rename to ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java
index 33e053cc2..e7ee06af9 100644
--- a/command/src/main/java/com/iluwatar/command/InvisibilitySpell.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceStatus.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,37 +21,27 @@
* THE SOFTWARE.
*/
-package com.iluwatar.command;
+package com.iluwatar.ambassador;
/**
- * InvisibilitySpell is a concrete command.
+ * Holds information regarding the status of the Remote Service.
+ *
+ * This Enum replaces the integer value previously
+ * stored in {@link RemoteServiceInterface} as SonarCloud was identifying
+ * it as an issue. All test cases have been checked after changes,
+ * without failures.
*/
-public class InvisibilitySpell implements Command {
- private Target target;
+public enum RemoteServiceStatus {
+ FAILURE(-1);
- @Override
- public void execute(Target target) {
- target.setVisibility(Visibility.INVISIBLE);
- this.target = target;
+ private final long remoteServiceStatusValue;
+
+ RemoteServiceStatus(long remoteServiceStatusValue) {
+ this.remoteServiceStatusValue = remoteServiceStatusValue;
}
- @Override
- public void undo() {
- if (target != null) {
- target.setVisibility(Visibility.VISIBLE);
- }
- }
-
- @Override
- public void redo() {
- if (target != null) {
- target.setVisibility(Visibility.INVISIBLE);
- }
- }
-
- @Override
- public String toString() {
- return "Invisibility spell";
+ public long getRemoteServiceStatusValue() {
+ return remoteServiceStatusValue;
}
}
diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java
index a9d34581c..bd8481d00 100644
--- a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,19 +23,19 @@
package com.iluwatar.ambassador;
+import static com.iluwatar.ambassador.RemoteServiceStatus.FAILURE;
import static java.lang.Thread.sleep;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* ServiceAmbassador provides an interface for a ({@link Client}) to access ({@link RemoteService}).
* The interface adds logging, latency testing and usage of the service in a safe way that will not
* add stress to the remote service when connectivity issues occur.
*/
+@Slf4j
public class ServiceAmbassador implements RemoteServiceInterface {
- private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAmbassador.class);
private static final int RETRIES = 3;
private static final int DELAY_MS = 3000;
@@ -52,26 +52,27 @@ public class ServiceAmbassador implements RemoteServiceInterface {
var result = RemoteService.getRemoteService().doRemoteFunction(value);
var timeTaken = System.currentTimeMillis() - startTime;
- LOGGER.info("Time taken (ms): " + timeTaken);
+ LOGGER.info("Time taken (ms): {}", timeTaken);
return result;
}
private long safeCall(int value) {
var retries = 0;
- var result = (long) FAILURE;
+ var result = FAILURE.getRemoteServiceStatusValue();
for (int i = 0; i < RETRIES; i++) {
if (retries >= RETRIES) {
- return FAILURE;
+ return FAILURE.getRemoteServiceStatusValue();
}
- if ((result = checkLatency(value)) == FAILURE) {
- LOGGER.info("Failed to reach remote: (" + (i + 1) + ")");
+ if ((result = checkLatency(value)) == FAILURE.getRemoteServiceStatusValue()) {
+ LOGGER.info("Failed to reach remote: ({})", i + 1);
retries++;
try {
sleep(DELAY_MS);
} catch (InterruptedException e) {
LOGGER.error("Thread sleep state interrupted", e);
+ Thread.currentThread().interrupt();
}
} else {
break;
diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/util/RandomProvider.java b/ambassador/src/main/java/com/iluwatar/ambassador/util/RandomProvider.java
index 5948472c0..9af9da500 100644
--- a/ambassador/src/main/java/com/iluwatar/ambassador/util/RandomProvider.java
+++ b/ambassador/src/main/java/com/iluwatar/ambassador/util/RandomProvider.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java
index c9a4d09b6..57658be39 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,13 +25,23 @@ package com.iluwatar.ambassador;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java
index 12a93a1cb..93ac792ae 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -37,6 +37,6 @@ class ClientTest {
Client client = new Client();
var result = client.useService(10);
- assertTrue(result == 100 || result == RemoteService.FAILURE);
+ assertTrue(result == 100 || result == RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue());
}
}
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
index 6c45acf66..c8c7d66ca 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -37,7 +37,7 @@ class RemoteServiceTest {
void testFailedCall() {
var remoteService = new RemoteService(new StaticRandomProvider(0.21));
var result = remoteService.doRemoteFunction(10);
- assertEquals(RemoteServiceInterface.FAILURE, result);
+ assertEquals(RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue(), result);
}
@Test
diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java
index 8eb55b30a..a17e36d74 100644
--- a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java
+++ b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -35,6 +35,6 @@ class ServiceAmbassadorTest {
@Test
void test() {
long result = new ServiceAmbassador().doRemoteFunction(10);
- assertTrue(result == 100 || result == RemoteServiceInterface.FAILURE);
+ assertTrue(result == 100 || result == RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue());
}
}
diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml
index 744023e90..26c567d95 100644
--- a/api-gateway/api-gateway-service/pom.xml
+++ b/api-gateway/api-gateway-service/pom.xml
@@ -2,7 +2,7 @@
+[](#contributors-)
+
+
+
+# مقدمة
+
+أنماط التصميم هي أفضل التدريبات التي يمكن للمبرمج استخدامها لحل المشكلات الشائعة عند تصميم تطبيق أو نظام.
+يمكن لأنماط التصميم تسريع عملية التطوير من خلال توفير نماذج تطوير مجربة ومثبتة ومفيدة.
+تساعد إعادة استخدام أنماط التصميم في منع المشكلات الدقيقة التي تسبب مشكلات كبيرة ، كما تعمل على تحسين قابلية قراءة الكود للمهندسين البرمجيات الذين هم على دراية بالأنماط.
+
+# البدء في التعلم
+
+يعرض هذا الموقع أنماط تصميم جافا. تم تطوير الحلول من قبل المبرمجين والمهندسين ذوي الخبرة من مجتمع المصادر المفتوحة. يمكن تصفح الأنماط من خلال أوصافها عالية المستوى أو بالنظر إلى كود المصدر الخاص بها. تم كتابة الشرح على أمثلة الكود المصدري جيدًا ويمكن اعتبارها برامج تعليمية حول كيفية تنفيذ نمط معين. نحن نستخدم تقنيات Java مفتوحة المصدر الأكثر شيوعًا والتي أثبتت جدارتها في مشاريع الجافا.
+قبل الغوص في المادة ، يجب أن تكون على دراية [بمبادئ تصميم البرامج المختلفة](https://java-design-patterns.com/principles/).
+
+يجب أن تكون جميع التصميمات بسيطة قدر الإمكان. يجب أن تبدأ بـ KISS و YAGNI وافعل أبسط شيء يمكن أن يعمل بهذه المبادىء. يجب إستخدام الأنماط فقط عند الحاجة إليها من أجل تمديد البرنامج بشكل عملي.
+
+بمجرد أن تصبح معتادًا على هذه المفاهيم ، يمكنك البدء في التعمق في [أنماط التصميم المتاحة](https://java-design-patterns.com/patterns/) من خلال أي من الأساليب التالية
+
+ابحث عن نمط محدد بالاسم. لا يمكنك العثور على واحد؟ الرجاء الإبلاغ عن نمط جديد [هنا](https://github.com/iluwatar/java-design-patterns/issues).
+استخدام علامات مثل Performance أو Gang of Four أو الوصول إلى البيانات.
+استخدام فئات الأنماط و Creational, Behavioral وغيرها.
+
+نأمل أن تجد الحلول الموجهة للكائنات المعروضة على هذا الموقع مفيدة في مشاريعك البرمجية وأن تستمتع بتعلمها بقدر ما قمنا بتطويرها.
+
+
+# كيف تساهم؟
+
+إذا كنت على استعداد للمساهمة في المشروع ، فستجد المعلومات ذات الصلة في [ويكي المطور الخاص بنا](https://github.com/iluwatar/java-design-patterns/wiki). سنساعدك ونجيب على أسئلتك في [غرفة الدردشة Gitter](https://gitter.im/iluwatar/java-design-patterns).
+
+
+# الترخيص
+
+هذا المشروع مرخص بموجب شروط ترخيص MIT.
\ No newline at end of file
diff --git a/arrange-act-assert/README.md b/arrange-act-assert/README.md
index 6b3cb4058..23efdd71e 100644
--- a/arrange-act-assert/README.md
+++ b/arrange-act-assert/README.md
@@ -81,10 +81,10 @@ Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the
separated steps for each unit test.
```java
-public class CashAAATest {
+class CashAAATest {
@Test
- public void testPlus() {
+ void testPlus() {
//Arrange
var cash = new Cash(3);
//Act
@@ -94,7 +94,7 @@ public class CashAAATest {
}
@Test
- public void testMinus() {
+ void testMinus() {
//Arrange
var cash = new Cash(8);
//Act
@@ -105,7 +105,7 @@ public class CashAAATest {
}
@Test
- public void testInsufficientMinus() {
+ void testInsufficientMinus() {
//Arrange
var cash = new Cash(1);
//Act
@@ -116,7 +116,7 @@ public class CashAAATest {
}
@Test
- public void testUpdate() {
+ void testUpdate() {
//Arrange
var cash = new Cash(5);
//Act
diff --git a/arrange-act-assert/pom.xml b/arrange-act-assert/pom.xml
index bb0387e7a..e23237197 100644
--- a/arrange-act-assert/pom.xml
+++ b/arrange-act-assert/pom.xml
@@ -2,7 +2,7 @@
+
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
async-method-invocation
@@ -36,11 +45,6 @@
mockito-core
test
-
- junit
- junit
- test
-
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
index 40c186704..b7d5e386b 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,14 +24,15 @@
package com.iluwatar.async.method.invocation;
import java.util.concurrent.Callable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
- * This application demonstrates the async method invocation pattern. Key parts of the pattern are
- * AsyncResult
which is an intermediate container for an asynchronously evaluated
- * value, AsyncCallback
which can be provided to be executed on task completion and
- * AsyncExecutor
that manages the execution of the async tasks.
+ * In this example, we are launching space rockets and deploying lunar rovers.
+ *
+ * The application demonstrates the async method invocation pattern. The key parts of the
+ * pattern are AsyncResult
which is an intermediate container for an asynchronously
+ * evaluated value, AsyncCallback
which can be provided to be executed on task
+ * completion and AsyncExecutor
that manages the execution of the async tasks.
*
*
The main method shows example flow of async invocations. The main thread starts multiple
* tasks with variable durations and then continues its own work. When the main thread has done it's
@@ -55,10 +56,9 @@ import org.slf4j.LoggerFactory;
* @see java.util.concurrent.CompletableFuture
* @see java.util.concurrent.ExecutorService
*/
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
-
/**
* Program entry point.
*/
@@ -70,13 +70,14 @@ public class App {
final var asyncResult1 = executor.startProcess(lazyval(10, 500));
final var asyncResult2 = executor.startProcess(lazyval("test", 300));
final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
- final var asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
+ final var asyncResult4 = executor.startProcess(lazyval(20, 400),
+ callback("Deploying lunar rover"));
final var asyncResult5 =
- executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
+ executor.startProcess(lazyval("callback", 600), callback("Deploying lunar rover"));
// emulate processing in the current thread while async tasks are running in their own threads
- Thread.sleep(350); // Oh boy I'm working hard here
- log("Some hard work done");
+ Thread.sleep(350); // Oh boy, we are working hard here
+ log("Mission command is sipping coffee");
// wait for completion of the tasks
final var result1 = executor.endProcess(asyncResult1);
@@ -86,9 +87,9 @@ public class App {
asyncResult5.await();
// log the results of the tasks, callbacks log immediately when complete
- log("Result 1: " + result1);
- log("Result 2: " + result2);
- log("Result 3: " + result3);
+ log("Space rocket <" + result1 + "> launch complete");
+ log("Space rocket <" + result2 + "> launch complete");
+ log("Space rocket <" + result3 + "> launch complete");
}
/**
@@ -101,7 +102,7 @@ public class App {
private static Callable lazyval(T value, long delayMillis) {
return () -> {
Thread.sleep(delayMillis);
- log("Task completed with: " + value);
+ log("Space rocket <" + value + "> launched successfully");
return value;
};
}
@@ -117,7 +118,7 @@ public class App {
if (ex.isPresent()) {
log(name + " failed: " + ex.map(Exception::getMessage).orElse(""));
} else {
- log(name + ": " + value);
+ log(name + " <" + value + ">");
}
};
}
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java
index 22b36134f..e51b0f190 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java
index 819ffd237..84cb7bec8 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
index 6aaf233b4..d27011a18 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
index e430e9ce4..b514a4000 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
index 830e66a2d..db49fae85 100644
--- a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
+++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,12 +25,24 @@ package com.iluwatar.async.method.invocation;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() throws Exception {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
+
}
}
diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
index 1e54747fa..b644e0e23 100644
--- a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
+++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/balking/README.md b/balking/README.md
index 22257ac7b..9d3550ad5 100644
--- a/balking/README.md
+++ b/balking/README.md
@@ -9,19 +9,131 @@ tags:
---
## Intent
-Balking Pattern is used to prevent an object from executing certain code if it is an
-incomplete or inappropriate state
+
+Balking Pattern is used to prevent an object from executing a certain code if it is in an incomplete
+or inappropriate state.
+
+## Explanation
+
+Real world example
+
+> There's a start-button in a washing machine to initiate the laundry washing. When the washing
+> machine is inactive the button works as expected, but if it's already washing the button does
+> nothing.
+
+In plain words
+
+> Using the balking pattern, a certain code executes only if the object is in particular state.
+
+Wikipedia says
+
+> The balking pattern is a software design pattern that only executes an action on an object when
+> the object is in a particular state. For example, if an object reads ZIP files and a calling
+> method invokes a get method on the object when the ZIP file is not open, the object would "balk"
+> at the request.
+
+**Programmatic Example**
+
+In this example implementation, `WashingMachine` is an object that has two states in which it can
+be: ENABLED and WASHING. If the machine is ENABLED, the state changes to WASHING using a thread-safe
+method. On the other hand, if it already has been washing and any other thread executes `wash()`
+it won't do that and returns without doing anything.
+
+Here are the relevant parts of the `WashingMachine` class.
+
+```java
+@Slf4j
+public class WashingMachine {
+
+ private final DelayProvider delayProvider;
+ private WashingMachineState washingMachineState;
+
+ public WashingMachine(DelayProvider delayProvider) {
+ this.delayProvider = delayProvider;
+ this.washingMachineState = WashingMachineState.ENABLED;
+ }
+
+ public WashingMachineState getWashingMachineState() {
+ return washingMachineState;
+ }
+
+ public void wash() {
+ synchronized (this) {
+ var machineState = getWashingMachineState();
+ LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
+ if (this.washingMachineState == WashingMachineState.WASHING) {
+ LOGGER.error("Cannot wash if the machine has been already washing!");
+ return;
+ }
+ this.washingMachineState = WashingMachineState.WASHING;
+ }
+ LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
+ this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
+ }
+
+ public synchronized void endOfWashing() {
+ washingMachineState = WashingMachineState.ENABLED;
+ LOGGER.info("{}: Washing completed.", Thread.currentThread().getId());
+ }
+}
+```
+
+Here's the simple `DelayProvider` interface used by the `WashingMachine`.
+
+```java
+public interface DelayProvider {
+ void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
+}
+```
+
+Now we introduce the application using the `WashingMachine`.
+
+```java
+ public static void main(String... args) {
+ final var washingMachine = new WashingMachine();
+ var executorService = Executors.newFixedThreadPool(3);
+ for (int i = 0; i < 3; i++) {
+ executorService.execute(washingMachine::wash);
+ }
+ executorService.shutdown();
+ try {
+ executorService.awaitTermination(10, TimeUnit.SECONDS);
+ } catch (InterruptedException ie) {
+ LOGGER.error("ERROR: Waiting on executor service shutdown!");
+ Thread.currentThread().interrupt();
+ }
+ }
+```
+
+Here is the console output of the program.
+
+```
+14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED
+14:02:52.272 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Doing the washing
+14:02:52.272 [pool-1-thread-3] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-3: Actual machine state: WASHING
+14:02:52.273 [pool-1-thread-3] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
+14:02:52.273 [pool-1-thread-1] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-1: Actual machine state: WASHING
+14:02:52.273 [pool-1-thread-1] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
+14:02:52.324 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - 14: Washing completed.
+```
## Class diagram
+

## Applicability
+
Use the Balking pattern when
-* you want to invoke an action on an object only when it is in a particular state
-* objects are generally only in a state that is prone to balking temporarily
-but for an unknown amount of time
+* You want to invoke an action on an object only when it is in a particular state
+* Objects are generally only in a state that is prone to balking temporarily but for an unknown
+ amount of time
## Related patterns
-* Guarded Suspension Pattern
-* Double Checked Locking Pattern
+
+* [Guarded Suspension Pattern](https://java-design-patterns.com/patterns/guarded-suspension/)
+* [Double Checked Locking Pattern](https://java-design-patterns.com/patterns/double-checked-locking/)
+
+## Credits
+
+* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, 2nd Edition, Volume 1](https://www.amazon.com/gp/product/0471227293/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0471227293&linkId=0e39a59ffaab93fb476036fecb637b99)
diff --git a/balking/pom.xml b/balking/pom.xml
index 964531692..1b200663b 100644
--- a/balking/pom.xml
+++ b/balking/pom.xml
@@ -1,26 +1,35 @@
-
+
java-design-patterns
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
4.0.0
diff --git a/balking/src/main/java/com/iluwatar/balking/App.java b/balking/src/main/java/com/iluwatar/balking/App.java
index 3e72acc59..644a344f4 100644
--- a/balking/src/main/java/com/iluwatar/balking/App.java
+++ b/balking/src/main/java/com/iluwatar/balking/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,28 +23,24 @@
package com.iluwatar.balking;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* In Balking Design Pattern if an object’s method is invoked when it is in an inappropriate state,
* then the method will return without doing anything. Objects that use this pattern are generally
* only in a state that is prone to balking temporarily but for an unknown amount of time
*
- * In this example implementation WashingMachine is an object that has two states in which it
- * can be: ENABLED and WASHING. If the machine is ENABLED the state is changed into WASHING that any
- * other thread can't invoke this action on this and then do the job. On the other hand if it have
- * been already washing and any other thread execute wash() it can't do that once again and returns
- * doing nothing.
+ *
In this example implementation, {@link WashingMachine} is an object that has two states in
+ * which it can be: ENABLED and WASHING. If the machine is ENABLED, the state changes to WASHING
+ * using a thread-safe method. On the other hand, if it already has been washing and any other
+ * thread executes {@link WashingMachine#wash()} it won't do that and returns without doing
+ * anything.
*/
-
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
-
/**
* Entry Point.
*
@@ -58,10 +54,12 @@ public class App {
}
executorService.shutdown();
try {
- executorService.awaitTermination(10, TimeUnit.SECONDS);
+ if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
+ executorService.shutdownNow();
+ }
} catch (InterruptedException ie) {
LOGGER.error("ERROR: Waiting on executor service shutdown!");
+ Thread.currentThread().interrupt();
}
}
-
}
diff --git a/balking/src/main/java/com/iluwatar/balking/DelayProvider.java b/balking/src/main/java/com/iluwatar/balking/DelayProvider.java
index ed05cd292..9b21e9574 100644
--- a/balking/src/main/java/com/iluwatar/balking/DelayProvider.java
+++ b/balking/src/main/java/com/iluwatar/balking/DelayProvider.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java
index b35bd99df..1da2b0204 100644
--- a/balking/src/main/java/com/iluwatar/balking/WashingMachine.java
+++ b/balking/src/main/java/com/iluwatar/balking/WashingMachine.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,15 +24,14 @@
package com.iluwatar.balking;
import java.util.concurrent.TimeUnit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* Washing machine class.
*/
+@Slf4j
public class WashingMachine {
- private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);
private final DelayProvider delayProvider;
private WashingMachineState washingMachineState;
@@ -44,7 +43,8 @@ public class WashingMachine {
try {
Thread.sleep(timeUnit.toMillis(interval));
} catch (InterruptedException ie) {
- ie.printStackTrace();
+ LOGGER.error("", ie);
+ Thread.currentThread().interrupt();
}
task.run();
});
@@ -71,7 +71,7 @@ public class WashingMachine {
var machineState = getWashingMachineState();
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
if (this.washingMachineState == WashingMachineState.WASHING) {
- LOGGER.error("ERROR: Cannot wash if the machine has been already washing!");
+ LOGGER.error("Cannot wash if the machine has been already washing!");
return;
}
this.washingMachineState = WashingMachineState.WASHING;
diff --git a/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java b/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java
index 664a4c0c9..f652a841f 100644
--- a/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java
+++ b/balking/src/main/java/com/iluwatar/balking/WashingMachineState.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -28,5 +28,6 @@ package com.iluwatar.balking;
* as well as during washing.
*/
public enum WashingMachineState {
- ENABLED, WASHING
+ ENABLED,
+ WASHING
}
diff --git a/balking/src/test/java/com/iluwatar/balking/AppTest.java b/balking/src/test/java/com/iluwatar/balking/AppTest.java
index 8c75a1f62..9c3fa683a 100644
--- a/balking/src/test/java/com/iluwatar/balking/AppTest.java
+++ b/balking/src/test/java/com/iluwatar/balking/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,15 +24,26 @@
package com.iluwatar.balking;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void main() {
- App.main();
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow((Executable) App::main);
}
}
\ No newline at end of file
diff --git a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java
index 9e218e3f0..8f41bf36e 100644
--- a/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java
+++ b/balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/bridge/README.md b/bridge/README.md
index 82c2f2735..12a6358f5 100644
--- a/bridge/README.md
+++ b/bridge/README.md
@@ -9,20 +9,26 @@ tags:
---
## Also known as
+
Handle/Body
## Intent
+
Decouple an abstraction from its implementation so that the two can vary independently.
## Explanation
Real world example
-> Consider you have a weapon with different enchantments and you are supposed to allow mixing different weapons with different enchantments. What would you do? Create multiple copies of each of the weapons for each of the enchantments or would you just create separate enchantment and set it for the weapon as needed? Bridge pattern allows you to do the second.
+> Consider you have a weapon with different enchantments, and you are supposed to allow mixing
+> different weapons with different enchantments. What would you do? Create multiple copies of each
+> of the weapons for each of the enchantments or would you just create separate enchantment and set
+> it for the weapon as needed? Bridge pattern allows you to do the second.
In Plain Words
-> Bridge pattern is about preferring composition over inheritance. Implementation details are pushed from a hierarchy to another object with a separate hierarchy.
+> Bridge pattern is about preferring composition over inheritance. Implementation details are pushed
+> from a hierarchy to another object with a separate hierarchy.
Wikipedia says
@@ -30,7 +36,7 @@ Wikipedia says
**Programmatic Example**
-Translating our weapon example from above. Here we have the `Weapon` hierarchy
+Translating our weapon example from above. Here we have the `Weapon` hierarchy:
```java
public interface Weapon {
@@ -105,7 +111,7 @@ public class Hammer implements Weapon {
}
```
-And the separate enchantment hierarchy
+Here's the separate enchantment hierarchy:
```java
public interface Enchantment {
@@ -151,7 +157,7 @@ public class SoulEatingEnchantment implements Enchantment {
}
```
-And both the hierarchies in action
+Here are both hierarchies in action:
```java
var enchantedSword = new Sword(new SoulEatingEnchantment());
@@ -178,18 +184,21 @@ hammer.unwield();
```
## Class diagram
+

## Applicability
+
Use the Bridge pattern when
-* you want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.
-* both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently
-* changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
-* you have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies
-* you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation.
+* You want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.
+* Both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently.
+* Changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
+* You have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies.
+* You want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation.
## Tutorial
+
* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java)
## Credits
diff --git a/bridge/pom.xml b/bridge/pom.xml
index 0664bc9b5..7fbed70e9 100644
--- a/bridge/pom.xml
+++ b/bridge/pom.xml
@@ -1,19 +1,28 @@
-
+
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
bridge
diff --git a/bridge/src/main/java/com/iluwatar/bridge/App.java b/bridge/src/main/java/com/iluwatar/bridge/App.java
index 3e89ef6f6..639d53f58 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/App.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,8 +23,7 @@
package com.iluwatar.bridge;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* Composition over inheritance. The Bridge pattern can also be thought of as two layers of
@@ -39,10 +38,9 @@ import org.slf4j.LoggerFactory;
* enchantments. We can easily combine any weapon with any enchantment using composition instead of
* creating deep class hierarchy.
*/
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
-
/**
* Program entry point.
*
diff --git a/bridge/src/main/java/com/iluwatar/bridge/Enchantment.java b/bridge/src/main/java/com/iluwatar/bridge/Enchantment.java
index 8388fe91e..3ddc34f9f 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/Enchantment.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/Enchantment.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/bridge/src/main/java/com/iluwatar/bridge/FlyingEnchantment.java b/bridge/src/main/java/com/iluwatar/bridge/FlyingEnchantment.java
index 772456b88..436b11a70 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/FlyingEnchantment.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/FlyingEnchantment.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,16 +23,14 @@
package com.iluwatar.bridge;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* FlyingEnchantment.
*/
+@Slf4j
public class FlyingEnchantment implements Enchantment {
- private static final Logger LOGGER = LoggerFactory.getLogger(FlyingEnchantment.class);
-
@Override
public void onActivate() {
LOGGER.info("The item begins to glow faintly.");
diff --git a/bridge/src/main/java/com/iluwatar/bridge/Hammer.java b/bridge/src/main/java/com/iluwatar/bridge/Hammer.java
index ffab542cb..834a2c54a 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/Hammer.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/Hammer.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,22 +23,18 @@
package com.iluwatar.bridge;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
/**
* Hammer.
*/
+@Slf4j
+@AllArgsConstructor
public class Hammer implements Weapon {
- private static final Logger LOGGER = LoggerFactory.getLogger(Hammer.class);
-
private final Enchantment enchantment;
- public Hammer(Enchantment enchantment) {
- this.enchantment = enchantment;
- }
-
@Override
public void wield() {
LOGGER.info("The hammer is wielded.");
diff --git a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingEnchantment.java b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingEnchantment.java
index ede98d2cb..746b827f6 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingEnchantment.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingEnchantment.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,16 +23,14 @@
package com.iluwatar.bridge;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* SoulEatingEnchantment.
*/
+@Slf4j
public class SoulEatingEnchantment implements Enchantment {
- private static final Logger LOGGER = LoggerFactory.getLogger(SoulEatingEnchantment.class);
-
@Override
public void onActivate() {
LOGGER.info("The item spreads bloodlust.");
diff --git a/bridge/src/main/java/com/iluwatar/bridge/Sword.java b/bridge/src/main/java/com/iluwatar/bridge/Sword.java
index 71f87a55d..ef9764eca 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/Sword.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/Sword.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,22 +23,18 @@
package com.iluwatar.bridge;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
/**
* Sword.
*/
+@Slf4j
+@AllArgsConstructor
public class Sword implements Weapon {
- private static final Logger LOGGER = LoggerFactory.getLogger(Sword.class);
-
private final Enchantment enchantment;
- public Sword(Enchantment enchantment) {
- this.enchantment = enchantment;
- }
-
@Override
public void wield() {
LOGGER.info("The sword is wielded.");
diff --git a/bridge/src/main/java/com/iluwatar/bridge/Weapon.java b/bridge/src/main/java/com/iluwatar/bridge/Weapon.java
index 76272332e..c5e1b5074 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/Weapon.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/Weapon.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/bridge/src/test/java/com/iluwatar/bridge/AppTest.java b/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
index d3edbb27c..da2019815 100644
--- a/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
+++ b/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,12 +25,22 @@ package com.iluwatar.bridge;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/bridge/src/test/java/com/iluwatar/bridge/HammerTest.java b/bridge/src/test/java/com/iluwatar/bridge/HammerTest.java
index b91f9f402..678913c2a 100644
--- a/bridge/src/test/java/com/iluwatar/bridge/HammerTest.java
+++ b/bridge/src/test/java/com/iluwatar/bridge/HammerTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/bridge/src/test/java/com/iluwatar/bridge/SwordTest.java b/bridge/src/test/java/com/iluwatar/bridge/SwordTest.java
index 95a6bc3d3..7bba8599c 100644
--- a/bridge/src/test/java/com/iluwatar/bridge/SwordTest.java
+++ b/bridge/src/test/java/com/iluwatar/bridge/SwordTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/bridge/src/test/java/com/iluwatar/bridge/WeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/WeaponTest.java
index 620e0104b..e8c4ef277 100644
--- a/bridge/src/test/java/com/iluwatar/bridge/WeaponTest.java
+++ b/bridge/src/test/java/com/iluwatar/bridge/WeaponTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/builder/README.md b/builder/README.md
index bb7426e35..008854ed7 100644
--- a/builder/README.md
+++ b/builder/README.md
@@ -9,36 +9,47 @@ tags:
---
## Intent
-Separate the construction of a complex object from its
-representation so that the same construction process can create different
-representations.
+
+Separate the construction of a complex object from its representation so that the same construction
+process can create different representations.
## Explanation
Real world example
-> Imagine a character generator for a role playing game. The easiest option is to let computer create the character for you. But if you want to select the character details like profession, gender, hair color etc. the character generation becomes a step-by-step process that completes when all the selections are ready.
+> Imagine a character generator for a role-playing game. The easiest option is to let the computer
+> create the character for you. If you want to manually select the character details like
+> profession, gender, hair color etc. the character generation becomes a step-by-step process that
+> completes when all the selections are ready.
In plain words
-> Allows you to create different flavors of an object while avoiding constructor pollution. Useful when there could be several flavors of an object. Or when there are a lot of steps involved in creation of an object.
+> Allows you to create different flavors of an object while avoiding constructor pollution. Useful
+> when there could be several flavors of an object. Or when there are a lot of steps involved in
+> creation of an object.
Wikipedia says
-> The builder pattern is an object creation software design pattern with the intentions of finding a solution to the telescoping constructor anti-pattern.
+> The builder pattern is an object creation software design pattern with the intentions of finding
+> a solution to the telescoping constructor anti-pattern.
-Having said that let me add a bit about what telescoping constructor anti-pattern is. At one point or the other we have all seen a constructor like below:
+Having said that let me add a bit about what telescoping constructor anti-pattern is. At one point
+or the other, we have all seen a constructor like below:
```java
public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) {
}
```
-As you can see the number of constructor parameters can quickly get out of hand and it might become difficult to understand the arrangement of parameters. Plus this parameter list could keep on growing if you would want to add more options in future. This is called telescoping constructor anti-pattern.
+As you can see the number of constructor parameters can quickly get out of hand, and it may become
+difficult to understand the arrangement of parameters. Plus this parameter list could keep on
+growing if you would want to add more options in the future. This is called telescoping constructor
+anti-pattern.
**Programmatic Example**
-The sane alternative is to use the Builder pattern. First of all we have our hero that we want to create
+The sane alternative is to use the Builder pattern. First of all we have our hero that we want to
+create:
```java
public final class Hero {
@@ -60,7 +71,7 @@ public final class Hero {
}
```
-And then we have the builder
+Then we have the builder:
```java
public static class Builder {
@@ -105,20 +116,22 @@ And then we have the builder
}
```
-And then it can be used as:
+Then it can be used as:
```java
var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build();
```
## Class diagram
+

## Applicability
+
Use the Builder pattern when
-* the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
-* the construction process must allow different representations for the object that's constructed
+* The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
+* The construction process must allow different representations for the object that's constructed
## Real world examples
diff --git a/builder/pom.xml b/builder/pom.xml
index dab9c66a7..439ce282a 100644
--- a/builder/pom.xml
+++ b/builder/pom.xml
@@ -1,19 +1,28 @@
-
+
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
builder
diff --git a/builder/src/main/java/com/iluwatar/builder/App.java b/builder/src/main/java/com/iluwatar/builder/App.java
index 76e514749..e62dd8ceb 100644
--- a/builder/src/main/java/com/iluwatar/builder/App.java
+++ b/builder/src/main/java/com/iluwatar/builder/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,8 +24,7 @@
package com.iluwatar.builder;
import com.iluwatar.builder.Hero.Builder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* The intention of the Builder pattern is to find a solution to the telescoping constructor
@@ -48,10 +47,9 @@ import org.slf4j.LoggerFactory;
* configuration for the {@link Hero} object can be done using the fluent {@link Builder} interface.
* When configuration is ready the build method is called to receive the final {@link Hero} object.
*/
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
-
/**
* Program entry point.
*
@@ -76,6 +74,5 @@ public class App {
.withWeapon(Weapon.BOW)
.build();
LOGGER.info(thief.toString());
-
}
}
diff --git a/builder/src/main/java/com/iluwatar/builder/Armor.java b/builder/src/main/java/com/iluwatar/builder/Armor.java
index 5a20a0824..0ed7be12e 100644
--- a/builder/src/main/java/com/iluwatar/builder/Armor.java
+++ b/builder/src/main/java/com/iluwatar/builder/Armor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,19 +23,21 @@
package com.iluwatar.builder;
+import lombok.AllArgsConstructor;
+
/**
* Armor enumeration.
*/
+@AllArgsConstructor
public enum Armor {
- CLOTHES("clothes"), LEATHER("leather"), CHAIN_MAIL("chain mail"), PLATE_MAIL("plate mail");
+ CLOTHES("clothes"),
+ LEATHER("leather"),
+ CHAIN_MAIL("chain mail"),
+ PLATE_MAIL("plate mail");
private final String title;
- Armor(String title) {
- this.title = title;
- }
-
@Override
public String toString() {
return title;
diff --git a/builder/src/main/java/com/iluwatar/builder/HairColor.java b/builder/src/main/java/com/iluwatar/builder/HairColor.java
index 1beccff5e..361bd5556 100644
--- a/builder/src/main/java/com/iluwatar/builder/HairColor.java
+++ b/builder/src/main/java/com/iluwatar/builder/HairColor.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -28,7 +28,11 @@ package com.iluwatar.builder;
*/
public enum HairColor {
- WHITE, BLOND, RED, BROWN, BLACK;
+ WHITE,
+ BLOND,
+ RED,
+ BROWN,
+ BLACK;
@Override
public String toString() {
diff --git a/builder/src/main/java/com/iluwatar/builder/HairType.java b/builder/src/main/java/com/iluwatar/builder/HairType.java
index 950f02a1b..9342031f6 100644
--- a/builder/src/main/java/com/iluwatar/builder/HairType.java
+++ b/builder/src/main/java/com/iluwatar/builder/HairType.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,20 +23,22 @@
package com.iluwatar.builder;
+import lombok.AllArgsConstructor;
+
/**
* HairType enumeration.
*/
+@AllArgsConstructor
public enum HairType {
- BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY(
- "long curly");
+ BALD("bald"),
+ SHORT("short"),
+ CURLY("curly"),
+ LONG_STRAIGHT("long straight"),
+ LONG_CURLY("long curly");
private final String title;
- HairType(String title) {
- this.title = title;
- }
-
@Override
public String toString() {
return title;
diff --git a/builder/src/main/java/com/iluwatar/builder/Hero.java b/builder/src/main/java/com/iluwatar/builder/Hero.java
index 86dc11034..7d45bd3df 100644
--- a/builder/src/main/java/com/iluwatar/builder/Hero.java
+++ b/builder/src/main/java/com/iluwatar/builder/Hero.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/builder/src/main/java/com/iluwatar/builder/Profession.java b/builder/src/main/java/com/iluwatar/builder/Profession.java
index 23b1ac220..f4c25fe89 100644
--- a/builder/src/main/java/com/iluwatar/builder/Profession.java
+++ b/builder/src/main/java/com/iluwatar/builder/Profession.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/builder/src/main/java/com/iluwatar/builder/Weapon.java b/builder/src/main/java/com/iluwatar/builder/Weapon.java
index 4ca78b95f..c80349287 100644
--- a/builder/src/main/java/com/iluwatar/builder/Weapon.java
+++ b/builder/src/main/java/com/iluwatar/builder/Weapon.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/builder/src/test/java/com/iluwatar/builder/AppTest.java b/builder/src/test/java/com/iluwatar/builder/AppTest.java
index 941f62f75..1c9ccddfa 100644
--- a/builder/src/test/java/com/iluwatar/builder/AppTest.java
+++ b/builder/src/test/java/com/iluwatar/builder/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,12 +25,22 @@ package com.iluwatar.builder;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/builder/src/test/java/com/iluwatar/builder/HeroTest.java b/builder/src/test/java/com/iluwatar/builder/HeroTest.java
index 97c984a70..f456c5ed9 100644
--- a/builder/src/test/java/com/iluwatar/builder/HeroTest.java
+++ b/builder/src/test/java/com/iluwatar/builder/HeroTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/business-delegate/README.md b/business-delegate/README.md
index b00c67819..886781632 100644
--- a/business-delegate/README.md
+++ b/business-delegate/README.md
@@ -9,21 +9,156 @@ tags:
---
## Intent
+
The Business Delegate pattern adds an abstraction layer between
presentation and business tiers. By using the pattern we gain loose coupling
between the tiers and encapsulate knowledge about how to locate, connect to,
and interact with the business objects that make up the application.
+## Explanation
+
+Real world example
+
+> A mobile phone application promises to stream any movie in existence to your phone. It captures
+> the user's search string and passes this on to the business delegate. The business delegate
+> selects the most suitable video streaming service and plays the video from there.
+
+In Plain Words
+
+> Business delegate adds an abstraction layer between the presentation and business tiers.
+
+Wikipedia says
+
+> Business delegate is a Java EE design pattern. This pattern is directing to reduce the coupling
+> in between business services and the connected presentation tier, and to hide the implementation
+> details of services (including lookup and accessibility of EJB architecture). Business delegates
+> acts as an adaptor to invoke business objects from the presentation tier.
+
+**Programmatic Example**
+
+First, we have an abstraction for video streaming services and a couple of implementations.
+
+```java
+public interface VideoStreamingService {
+ void doProcessing();
+}
+
+@Slf4j
+public class NetflixService implements VideoStreamingService {
+ @Override
+ public void doProcessing() {
+ LOGGER.info("NetflixService is now processing");
+ }
+}
+
+@Slf4j
+public class YouTubeService implements VideoStreamingService {
+ @Override
+ public void doProcessing() {
+ LOGGER.info("YouTubeService is now processing");
+ }
+}
+```
+
+Then we have a lookup service that decides which video streaming service is used.
+
+```java
+@Setter
+public class BusinessLookup {
+
+ private NetflixService netflixService;
+ private YouTubeService youTubeService;
+
+ public VideoStreamingService getBusinessService(String movie) {
+ if (movie.toLowerCase(Locale.ROOT).contains("die hard")) {
+ return netflixService;
+ } else {
+ return youTubeService;
+ }
+ }
+}
+```
+
+The business delegate uses a business lookup to route movie playback requests to a suitable
+video streaming service.
+
+```java
+@Setter
+public class BusinessDelegate {
+
+ private BusinessLookup lookupService;
+
+ public void playbackMovie(String movie) {
+ VideoStreamingService videoStreamingService = lookupService.getBusinessService(movie);
+ videoStreamingService.doProcessing();
+ }
+}
+```
+
+The mobile client utilizes business delegate to call the business tier.
+
+```java
+public class MobileClient {
+
+ private final BusinessDelegate businessDelegate;
+
+ public MobileClient(BusinessDelegate businessDelegate) {
+ this.businessDelegate = businessDelegate;
+ }
+
+ public void playbackMovie(String movie) {
+ businessDelegate.playbackMovie(movie);
+ }
+}
+```
+
+Finally, we can show the full example in action.
+
+```java
+ public static void main(String[] args) {
+
+ // prepare the objects
+ var businessDelegate = new BusinessDelegate();
+ var businessLookup = new BusinessLookup();
+ businessLookup.setNetflixService(new NetflixService());
+ businessLookup.setYouTubeService(new YouTubeService());
+ businessDelegate.setLookupService(businessLookup);
+
+ // create the client and use the business delegate
+ var client = new MobileClient(businessDelegate);
+ client.playbackMovie("Die Hard 2");
+ client.playbackMovie("Maradona: The Greatest Ever");
+ }
+```
+
+Here is the console output.
+
+```
+21:15:33.790 [main] INFO com.iluwatar.business.delegate.NetflixService - NetflixService is now processing
+21:15:33.794 [main] INFO com.iluwatar.business.delegate.YouTubeService - YouTubeService is now processing
+```
+
## Class diagram
-
+
+
+
+## Related patterns
+
+* [Service locator pattern](https://java-design-patterns.com/patterns/service-locator/)
## Applicability
+
Use the Business Delegate pattern when
-* you want loose coupling between presentation and business tiers
-* you want to orchestrate calls to multiple business services
-* you want to encapsulate service lookups and service calls
+* You want loose coupling between presentation and business tiers
+* You want to orchestrate calls to multiple business services
+* You want to encapsulate service lookups and service calls
+
+## Tutorials
+
+* [Business Delegate Pattern at TutorialsPoint](https://www.tutorialspoint.com/design_pattern/business_delegate_pattern.htm)
## Credits
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+* [Core J2EE Patterns: Best Practices and Design Strategies](https://www.amazon.com/gp/product/0130648841/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0130648841&linkId=a0100de2b28c71ede8db1757fb2b5947)
diff --git a/business-delegate/etc/business-delegate.png b/business-delegate/etc/business-delegate.png
deleted file mode 100644
index 928cf9346..000000000
Binary files a/business-delegate/etc/business-delegate.png and /dev/null differ
diff --git a/business-delegate/etc/business-delegate.ucls b/business-delegate/etc/business-delegate.ucls
deleted file mode 100644
index 668a6579e..000000000
--- a/business-delegate/etc/business-delegate.ucls
+++ /dev/null
@@ -1,136 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/business-delegate/etc/business-delegate.urm.png b/business-delegate/etc/business-delegate.urm.png
new file mode 100644
index 000000000..4dca6c263
Binary files /dev/null and b/business-delegate/etc/business-delegate.urm.png differ
diff --git a/business-delegate/etc/business-delegate.urm.puml b/business-delegate/etc/business-delegate.urm.puml
index 40aa2d6f0..407e3e12d 100644
--- a/business-delegate/etc/business-delegate.urm.puml
+++ b/business-delegate/etc/business-delegate.urm.puml
@@ -5,53 +5,42 @@ package com.iluwatar.business.delegate {
+ main(args : String[]) {static}
}
class BusinessDelegate {
- - businessService : BusinessService
- lookupService : BusinessLookup
- - serviceType : ServiceType
+ BusinessDelegate()
- + doTask()
- + setLookupService(businessLookup : BusinessLookup)
- + setServiceType(serviceType : ServiceType)
+ + playbackMovie(movie : String)
+ + setLookupService(lookupService : BusinessLookup)
}
class BusinessLookup {
- - ejbService : EjbService
- - jmsService : JmsService
+ - netflixService : NetflixService
+ - youTubeService : YouTubeService
+ BusinessLookup()
- + getBusinessService(serviceType : ServiceType) : BusinessService
- + setEjbService(ejbService : EjbService)
- + setJmsService(jmsService : JmsService)
+ + getBusinessService(movie : String) : VideoStreamingService
+ + setNetflixService(netflixService : NetflixService)
+ + setYouTubeService(youTubeService : YouTubeService)
}
- interface BusinessService {
+ class MobileClient {
+ - businessDelegate : BusinessDelegate
+ + MobileClient(businessDelegate : BusinessDelegate)
+ + playbackMovie(movie : String)
+ }
+ class NetflixService {
+ - LOGGER : Logger {static}
+ + NetflixService()
+ + doProcessing()
+ }
+ interface VideoStreamingService {
+ doProcessing() {abstract}
}
- class Client {
- - businessDelegate : BusinessDelegate
- + Client(businessDelegate : BusinessDelegate)
- + doTask()
- }
- class EjbService {
+ class YouTubeService {
- LOGGER : Logger {static}
- + EjbService()
+ + YouTubeService()
+ doProcessing()
}
- class JmsService {
- - LOGGER : Logger {static}
- + JmsService()
- + doProcessing()
- }
- enum ServiceType {
- + EJB {static}
- + JMS {static}
- + valueOf(name : String) : ServiceType {static}
- + values() : ServiceType[] {static}
- }
}
-BusinessLookup --> "-ejbService" EjbService
-BusinessDelegate --> "-serviceType" ServiceType
-Client --> "-businessDelegate" BusinessDelegate
-BusinessDelegate --> "-businessService" BusinessService
+BusinessLookup --> "-netflixService" NetflixService
+BusinessLookup --> "-youTubeService" YouTubeService
+MobileClient --> "-businessDelegate" BusinessDelegate
BusinessDelegate --> "-lookupService" BusinessLookup
-BusinessLookup --> "-jmsService" JmsService
-EjbService ..|> BusinessService
-JmsService ..|> BusinessService
+NetflixService ..|> VideoStreamingService
+YouTubeService ..|> VideoStreamingService
@enduml
\ No newline at end of file
diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml
index 26987c73a..aa70c99ec 100644
--- a/business-delegate/pom.xml
+++ b/business-delegate/pom.xml
@@ -1,19 +1,28 @@
-
+
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
business-delegate
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/App.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/App.java
index 115234df7..e87ca9c64 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/App.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -33,9 +33,9 @@ package com.iluwatar.business.delegate;
* retrieved through service lookups. The Business Delegate itself may contain business logic too
* potentially tying together multiple service calls, exception handling, retrying etc.
*
- * In this example the client ({@link Client}) utilizes a business delegate (
- * {@link BusinessDelegate}) to execute a task. The Business Delegate then selects the appropriate
- * service and makes the service call.
+ *
In this example the client ({@link MobileClient}) utilizes a business delegate (
+ * {@link BusinessDelegate}) to search for movies in video streaming services. The Business Delegate
+ * then selects the appropriate service and makes the service call.
*/
public class App {
@@ -46,18 +46,16 @@ public class App {
*/
public static void main(String[] args) {
+ // prepare the objects
var businessDelegate = new BusinessDelegate();
var businessLookup = new BusinessLookup();
- businessLookup.setEjbService(new EjbService());
- businessLookup.setJmsService(new JmsService());
-
+ businessLookup.setNetflixService(new NetflixService());
+ businessLookup.setYouTubeService(new YouTubeService());
businessDelegate.setLookupService(businessLookup);
- businessDelegate.setServiceType(ServiceType.EJB);
- var client = new Client(businessDelegate);
- client.doTask();
-
- businessDelegate.setServiceType(ServiceType.JMS);
- client.doTask();
+ // create the client and use the business delegate
+ var client = new MobileClient(businessDelegate);
+ client.playbackMovie("Die Hard 2");
+ client.playbackMovie("Maradona: The Greatest Ever");
}
}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java
index c39a2ad39..6246145e7 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,25 +23,18 @@
package com.iluwatar.business.delegate;
+import lombok.Setter;
+
/**
* BusinessDelegate separates the presentation and business tiers.
*/
+@Setter
public class BusinessDelegate {
private BusinessLookup lookupService;
- private BusinessService businessService;
- private ServiceType serviceType;
- public void setLookupService(BusinessLookup businessLookup) {
- this.lookupService = businessLookup;
- }
-
- public void setServiceType(ServiceType serviceType) {
- this.serviceType = serviceType;
- }
-
- public void doTask() {
- businessService = lookupService.getBusinessService(serviceType);
- businessService.doProcessing();
+ public void playbackMovie(String movie) {
+ VideoStreamingService videoStreamingService = lookupService.getBusinessService(movie);
+ videoStreamingService.doProcessing();
}
}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java
index 489caa23c..0369c04e8 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,34 +23,30 @@
package com.iluwatar.business.delegate;
+import java.util.Locale;
+import lombok.Setter;
+
/**
* Class for performing service lookups.
*/
+@Setter
public class BusinessLookup {
- private EjbService ejbService;
+ private NetflixService netflixService;
- private JmsService jmsService;
+ private YouTubeService youTubeService;
/**
- * Gets service instance based on service type.
+ * Gets service instance based on given movie search string.
*
- * @param serviceType Type of service instance to be returned.
+ * @param movie Search string for the movie.
* @return Service instance.
*/
- public BusinessService getBusinessService(ServiceType serviceType) {
- if (serviceType.equals(ServiceType.EJB)) {
- return ejbService;
+ public VideoStreamingService getBusinessService(String movie) {
+ if (movie.toLowerCase(Locale.ROOT).contains("die hard")) {
+ return netflixService;
} else {
- return jmsService;
+ return youTubeService;
}
}
-
- public void setJmsService(JmsService jmsService) {
- this.jmsService = jmsService;
- }
-
- public void setEjbService(EjbService ejbService) {
- this.ejbService = ejbService;
- }
}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/MobileClient.java
similarity index 81%
rename from business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java
rename to business-delegate/src/main/java/com/iluwatar/business/delegate/MobileClient.java
index 2c13bc149..2cfb6f344 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/MobileClient.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,17 +24,17 @@
package com.iluwatar.business.delegate;
/**
- * Client utilizes BusinessDelegate to call the business tier.
+ * MobileClient utilizes BusinessDelegate to call the business tier.
*/
-public class Client {
+public class MobileClient {
private final BusinessDelegate businessDelegate;
- public Client(BusinessDelegate businessDelegate) {
+ public MobileClient(BusinessDelegate businessDelegate) {
this.businessDelegate = businessDelegate;
}
- public void doTask() {
- businessDelegate.doTask();
+ public void playbackMovie(String movie) {
+ businessDelegate.playbackMovie(movie);
}
}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/NetflixService.java
similarity index 79%
rename from business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java
rename to business-delegate/src/main/java/com/iluwatar/business/delegate/NetflixService.java
index 2317d783a..ae9da8747 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/NetflixService.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,18 +23,16 @@
package com.iluwatar.business.delegate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
- * Service JMS implementation.
+ * NetflixService implementation.
*/
-public class JmsService implements BusinessService {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(JmsService.class);
+@Slf4j
+public class NetflixService implements VideoStreamingService {
@Override
public void doProcessing() {
- LOGGER.info("JmsService is now processing");
+ LOGGER.info("NetflixService is now processing");
}
}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/VideoStreamingService.java
similarity index 89%
rename from business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessService.java
rename to business-delegate/src/main/java/com/iluwatar/business/delegate/VideoStreamingService.java
index 3094d3f6e..3c8b7e3fb 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessService.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/VideoStreamingService.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,9 +24,9 @@
package com.iluwatar.business.delegate;
/**
- * Interface for service implementations.
+ * Interface for video streaming service implementations.
*/
-public interface BusinessService {
+public interface VideoStreamingService {
void doProcessing();
}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/YouTubeService.java
similarity index 79%
rename from business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java
rename to business-delegate/src/main/java/com/iluwatar/business/delegate/YouTubeService.java
index 6f39abb1a..aa79e7309 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/YouTubeService.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,18 +23,16 @@
package com.iluwatar.business.delegate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
- * Service EJB implementation.
+ * YouTubeService implementation.
*/
-public class EjbService implements BusinessService {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(EjbService.class);
+@Slf4j
+public class YouTubeService implements VideoStreamingService {
@Override
public void doProcessing() {
- LOGGER.info("EjbService is now processing");
+ LOGGER.info("YouTubeService is now processing");
}
}
diff --git a/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java b/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
index 48e756acb..f70b67814 100644
--- a/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
+++ b/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -27,13 +27,23 @@ import org.junit.jupiter.api.Test;
import java.io.IOException;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Tests that Business Delegate example runs without errors.
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+
@Test
- public void test() throws IOException {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/business-delegate/src/test/java/com/iluwatar/business/delegate/BusinessDelegateTest.java b/business-delegate/src/test/java/com/iluwatar/business/delegate/BusinessDelegateTest.java
index 10815ad3a..8cd5e2021 100644
--- a/business-delegate/src/test/java/com/iluwatar/business/delegate/BusinessDelegateTest.java
+++ b/business-delegate/src/test/java/com/iluwatar/business/delegate/BusinessDelegateTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -26,27 +26,20 @@ package com.iluwatar.business.delegate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
- * The Business Delegate pattern adds an abstraction layer between the presentation and business
- * tiers. By using the pattern we gain loose coupling between the tiers. The Business Delegate
- * encapsulates knowledge about how to locate, connect to, and interact with the business objects
- * that make up the application.
- *
- *
Some of the services the Business Delegate uses are instantiated directly, and some can be
- * retrieved through service lookups. The Business Delegate itself may contain business logic too
- * potentially tying together multiple service calls, exception handling, retrying etc.
+ * Tests for the {@link BusinessDelegate}
*/
-public class BusinessDelegateTest {
+class BusinessDelegateTest {
- private EjbService ejbService;
+ private NetflixService netflixService;
- private JmsService jmsService;
-
- private BusinessLookup businessLookup;
+ private YouTubeService youTubeService;
private BusinessDelegate businessDelegate;
@@ -56,46 +49,40 @@ public class BusinessDelegateTest {
*/
@BeforeEach
public void setup() {
- ejbService = spy(new EjbService());
- jmsService = spy(new JmsService());
+ netflixService = spy(new NetflixService());
+ youTubeService = spy(new YouTubeService());
- businessLookup = spy(new BusinessLookup());
- businessLookup.setEjbService(ejbService);
- businessLookup.setJmsService(jmsService);
+ BusinessLookup businessLookup = spy(new BusinessLookup());
+ businessLookup.setNetflixService(netflixService);
+ businessLookup.setYouTubeService(youTubeService);
businessDelegate = spy(new BusinessDelegate());
businessDelegate.setLookupService(businessLookup);
}
/**
- * In this example the client ({@link Client}) utilizes a business delegate (
+ * In this example the client ({@link MobileClient}) utilizes a business delegate (
* {@link BusinessDelegate}) to execute a task. The Business Delegate then selects the appropriate
* service and makes the service call.
*/
@Test
- public void testBusinessDelegate() {
+ void testBusinessDelegate() {
// setup a client object
- var client = new Client(businessDelegate);
-
- // set the service type
- businessDelegate.setServiceType(ServiceType.EJB);
+ var client = new MobileClient(businessDelegate);
// action
- client.doTask();
+ client.playbackMovie("Die hard");
- // verifying that the businessDelegate was used by client during doTask() method.
- verify(businessDelegate).doTask();
- verify(ejbService).doProcessing();
-
- // set the service type
- businessDelegate.setServiceType(ServiceType.JMS);
+ // verifying that the businessDelegate was used by client during playbackMovie() method.
+ verify(businessDelegate).playbackMovie(anyString());
+ verify(netflixService).doProcessing();
// action
- client.doTask();
+ client.playbackMovie("Maradona");
// verifying that the businessDelegate was used by client during doTask() method.
- verify(businessDelegate, times(2)).doTask();
- verify(jmsService).doProcessing();
+ verify(businessDelegate, times(2)).playbackMovie(anyString());
+ verify(youTubeService).doProcessing();
}
}
diff --git a/bytecode/README.md b/bytecode/README.md
index ee3f96ed8..115f0b96a 100644
--- a/bytecode/README.md
+++ b/bytecode/README.md
@@ -9,18 +9,234 @@ tags:
---
## Intent
-Allows to encode behaviour as instructions for virtual machine.
+
+Allows encoding behavior as instructions for a virtual machine.
+
+## Explanation
+
+Real world example
+
+> A team is working on a new game where wizards battle against each other. The wizard behavior
+> needs to be carefully adjusted and iterated hundreds of times through playtesting. It's not
+> optimal to ask the programmer to make changes each time the game designer wants to vary the
+> behavior, so the wizard behavior is implemented as a data-driven virtual machine.
+
+In plain words
+
+> Bytecode pattern enables behavior driven by data instead of code.
+
+[Gameprogrammingpatterns.com](https://gameprogrammingpatterns.com/bytecode.html) documentation
+states:
+
+> An instruction set defines the low-level operations that can be performed. A series of
+> instructions is encoded as a sequence of bytes. A virtual machine executes these instructions one
+> at a time, using a stack for intermediate values. By combining instructions, complex high-level
+> behavior can be defined.
+
+**Programmatic Example**
+
+One of the most important game objects is the `Wizard` class.
+
+```java
+@AllArgsConstructor
+@Setter
+@Getter
+@Slf4j
+public class Wizard {
+
+ private int health;
+ private int agility;
+ private int wisdom;
+ private int numberOfPlayedSounds;
+ private int numberOfSpawnedParticles;
+
+ public void playSound() {
+ LOGGER.info("Playing sound");
+ numberOfPlayedSounds++;
+ }
+
+ public void spawnParticles() {
+ LOGGER.info("Spawning particles");
+ numberOfSpawnedParticles++;
+ }
+}
+```
+
+Next, we show the available instructions for our virtual machine. Each of the instructions has its
+own semantics on how it operates with the stack data. For example, the ADD instruction takes the top
+two items from the stack, adds them together and pushes the result to the stack.
+
+```java
+@AllArgsConstructor
+@Getter
+public enum Instruction {
+
+ LITERAL(1), // e.g. "LITERAL 0", push 0 to stack
+ SET_HEALTH(2), // e.g. "SET_HEALTH", pop health and wizard number, call set health
+ SET_WISDOM(3), // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom
+ SET_AGILITY(4), // e.g. "SET_AGILITY", pop agility and wizard number, call set agility
+ PLAY_SOUND(5), // e.g. "PLAY_SOUND", pop value as wizard number, call play sound
+ SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles
+ GET_HEALTH(7), // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health
+ GET_AGILITY(8), // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility
+ GET_WISDOM(9), // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom
+ ADD(10), // e.g. "ADD", pop 2 values, push their sum
+ DIVIDE(11); // e.g. "DIVIDE", pop 2 values, push their division
+ // ...
+}
+```
+
+At the heart of our example is the `VirtualMachine` class. It takes instructions as input and
+executes them to provide the game object behavior.
+
+```java
+@Getter
+@Slf4j
+public class VirtualMachine {
+
+ private final Stack stack = new Stack<>();
+
+ private final Wizard[] wizards = new Wizard[2];
+
+ public VirtualMachine() {
+ wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
+ 0, 0);
+ wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
+ 0, 0);
+ }
+
+ public VirtualMachine(Wizard wizard1, Wizard wizard2) {
+ wizards[0] = wizard1;
+ wizards[1] = wizard2;
+ }
+
+ public void execute(int[] bytecode) {
+ for (var i = 0; i < bytecode.length; i++) {
+ Instruction instruction = Instruction.getInstruction(bytecode[i]);
+ switch (instruction) {
+ case LITERAL:
+ // Read the next byte from the bytecode.
+ int value = bytecode[++i];
+ // Push the next value to stack
+ stack.push(value);
+ break;
+ case SET_AGILITY:
+ var amount = stack.pop();
+ var wizard = stack.pop();
+ setAgility(wizard, amount);
+ break;
+ case SET_WISDOM:
+ amount = stack.pop();
+ wizard = stack.pop();
+ setWisdom(wizard, amount);
+ break;
+ case SET_HEALTH:
+ amount = stack.pop();
+ wizard = stack.pop();
+ setHealth(wizard, amount);
+ break;
+ case GET_HEALTH:
+ wizard = stack.pop();
+ stack.push(getHealth(wizard));
+ break;
+ case GET_AGILITY:
+ wizard = stack.pop();
+ stack.push(getAgility(wizard));
+ break;
+ case GET_WISDOM:
+ wizard = stack.pop();
+ stack.push(getWisdom(wizard));
+ break;
+ case ADD:
+ var a = stack.pop();
+ var b = stack.pop();
+ stack.push(a + b);
+ break;
+ case DIVIDE:
+ a = stack.pop();
+ b = stack.pop();
+ stack.push(b / a);
+ break;
+ case PLAY_SOUND:
+ wizard = stack.pop();
+ getWizards()[wizard].playSound();
+ break;
+ case SPAWN_PARTICLES:
+ wizard = stack.pop();
+ getWizards()[wizard].spawnParticles();
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid instruction value");
+ }
+ LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack());
+ }
+ }
+
+ public void setHealth(int wizard, int amount) {
+ wizards[wizard].setHealth(amount);
+ }
+ // other setters ->
+ // ...
+}
+```
+
+Now we can show the full example utilizing the virtual machine.
+
+```java
+ public static void main(String[] args) {
+
+ var vm = new VirtualMachine(
+ new Wizard(45, 7, 11, 0, 0),
+ new Wizard(36, 18, 8, 0, 0));
+
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("GET_HEALTH"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("GET_AGILITY"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("GET_WISDOM"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 2"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("DIVIDE"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("SET_HEALTH"));
+ }
+```
+
+Here is the console output.
+
+```
+16:20:10.193 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0]
+16:20:10.196 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 0]
+16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_HEALTH, Stack contains [0, 45]
+16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 0]
+16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_AGILITY, Stack contains [0, 45, 7]
+16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 7, 0]
+16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed GET_WISDOM, Stack contains [0, 45, 7, 11]
+16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 45, 18]
+16:20:10.197 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed LITERAL, Stack contains [0, 45, 18, 2]
+16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed DIVIDE, Stack contains [0, 45, 9]
+16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed ADD, Stack contains [0, 54]
+16:20:10.198 [main] INFO com.iluwatar.bytecode.VirtualMachine - Executed SET_HEALTH, Stack contains []
+```
## Class diagram
+

## Applicability
+
Use the Bytecode pattern when you have a lot of behavior you need to define and your
game’s implementation language isn’t a good fit because:
-* it’s too low-level, making it tedious or error-prone to program in.
-* iterating on it takes too long due to slow compile times or other tooling issues.
-* it has too much trust. If you want to ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of the codebase.
+* It’s too low-level, making it tedious or error-prone to program in.
+* Iterating on it takes too long due to slow compile times or other tooling issues.
+* It has too much trust. If you want to ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of the codebase.
+
+## Related patterns
+
+* [Interpreter](https://java-design-patterns.com/patterns/interpreter/)
## Credits
diff --git a/bytecode/etc/bytecode.png b/bytecode/etc/bytecode.png
deleted file mode 100644
index 31b6bc6ed..000000000
Binary files a/bytecode/etc/bytecode.png and /dev/null differ
diff --git a/bytecode/etc/bytecode.ucls b/bytecode/etc/bytecode.ucls
deleted file mode 100644
index 3ec390458..000000000
--- a/bytecode/etc/bytecode.ucls
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/bytecode/etc/bytecode.urm.png b/bytecode/etc/bytecode.urm.png
index 82036a78a..51335fa0a 100644
Binary files a/bytecode/etc/bytecode.urm.png and b/bytecode/etc/bytecode.urm.png differ
diff --git a/bytecode/etc/bytecode.urm.puml b/bytecode/etc/bytecode.urm.puml
index d675ae398..224e909ef 100644
--- a/bytecode/etc/bytecode.urm.puml
+++ b/bytecode/etc/bytecode.urm.puml
@@ -3,7 +3,6 @@ package com.iluwatar.bytecode {
class App {
- LOGGER : Logger {static}
+ App()
- - interpretInstruction(instruction : String, vm : VirtualMachine) {static}
+ main(args : String[]) {static}
}
enum Instruction {
@@ -18,22 +17,25 @@ package com.iluwatar.bytecode {
+ SET_HEALTH {static}
+ SET_WISDOM {static}
+ SPAWN_PARTICLES {static}
- - value : int
+ - intValue : int
+ getInstruction(value : int) : Instruction {static}
+ getIntValue() : int
+ valueOf(name : String) : Instruction {static}
+ values() : Instruction[] {static}
}
class VirtualMachine {
+ - LOGGER : Logger {static}
- stack : Stack
- wizards : Wizard[]
+ VirtualMachine()
+ + VirtualMachine(wizard1 : Wizard, wizard2 : Wizard)
+ execute(bytecode : int[])
+ getAgility(wizard : int) : int
+ getHealth(wizard : int) : int
+ getStack() : Stack
+ getWisdom(wizard : int) : int
+ getWizards() : Wizard[]
+ - randomInt(min : int, max : int) : int
+ setAgility(wizard : int, amount : int)
+ setHealth(wizard : int, amount : int)
+ setWisdom(wizard : int, amount : int)
@@ -45,7 +47,7 @@ package com.iluwatar.bytecode {
- numberOfPlayedSounds : int
- numberOfSpawnedParticles : int
- wisdom : int
- + Wizard()
+ + Wizard(health : int, agility : int, wisdom : int, numberOfPlayedSounds : int, numberOfSpawnedParticles : int)
+ getAgility() : int
+ getHealth() : int
+ getNumberOfPlayedSounds() : int
@@ -54,6 +56,8 @@ package com.iluwatar.bytecode {
+ playSound()
+ setAgility(agility : int)
+ setHealth(health : int)
+ + setNumberOfPlayedSounds(numberOfPlayedSounds : int)
+ + setNumberOfSpawnedParticles(numberOfSpawnedParticles : int)
+ setWisdom(wisdom : int)
+ spawnParticles()
}
diff --git a/bytecode/pom.xml b/bytecode/pom.xml
index f6be69cee..3655ebbb4 100644
--- a/bytecode/pom.xml
+++ b/bytecode/pom.xml
@@ -1,26 +1,35 @@
-
+
java-design-patterns
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
4.0.0
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/App.java b/bytecode/src/main/java/com/iluwatar/bytecode/App.java
index 04f473cee..f76a8e6a4 100644
--- a/bytecode/src/main/java/com/iluwatar/bytecode/App.java
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,8 +24,7 @@
package com.iluwatar.bytecode;
import com.iluwatar.bytecode.util.InstructionConverterUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* The intention of Bytecode pattern is to give behavior the flexibility of data by encoding it as
@@ -40,8 +39,8 @@ import org.slf4j.LoggerFactory;
* ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of
* the codebase.
*/
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Main app method.
@@ -50,31 +49,21 @@ public class App {
*/
public static void main(String[] args) {
- var wizard = new Wizard();
- wizard.setHealth(45);
- wizard.setAgility(7);
- wizard.setWisdom(11);
+ var vm = new VirtualMachine(
+ new Wizard(45, 7, 11, 0, 0),
+ new Wizard(36, 18, 8, 0, 0));
- var vm = new VirtualMachine();
- vm.getWizards()[0] = wizard;
-
- interpretInstruction("LITERAL 0", vm);
- interpretInstruction("LITERAL 0", vm);
- interpretInstruction("GET_HEALTH", vm);
- interpretInstruction("LITERAL 0", vm);
- interpretInstruction("GET_AGILITY", vm);
- interpretInstruction("LITERAL 0", vm);
- interpretInstruction("GET_WISDOM ", vm);
- interpretInstruction("ADD", vm);
- interpretInstruction("LITERAL 2", vm);
- interpretInstruction("DIVIDE", vm);
- interpretInstruction("ADD", vm);
- interpretInstruction("SET_HEALTH", vm);
- }
-
- private static void interpretInstruction(String instruction, VirtualMachine vm) {
- vm.execute(InstructionConverterUtil.convertToByteCode(instruction));
- var stack = vm.getStack();
- LOGGER.info(instruction + String.format("%" + (12 - instruction.length()) + "s", "") + stack);
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("GET_HEALTH"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("GET_AGILITY"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 0"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("GET_WISDOM"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("LITERAL 2"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("DIVIDE"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("ADD"));
+ vm.execute(InstructionConverterUtil.convertToByteCode("SET_HEALTH"));
}
}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/Instruction.java b/bytecode/src/main/java/com/iluwatar/bytecode/Instruction.java
index eeaf16846..ad16fb7f2 100644
--- a/bytecode/src/main/java/com/iluwatar/bytecode/Instruction.java
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/Instruction.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,32 +23,29 @@
package com.iluwatar.bytecode;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
/**
* Representation of instructions understandable by virtual machine.
*/
+@AllArgsConstructor
+@Getter
public enum Instruction {
- LITERAL(1),
- SET_HEALTH(2),
- SET_WISDOM(3),
- SET_AGILITY(4),
- PLAY_SOUND(5),
- SPAWN_PARTICLES(6),
- GET_HEALTH(7),
- GET_AGILITY(8),
- GET_WISDOM(9),
- ADD(10),
- DIVIDE(11);
+ LITERAL(1), // e.g. "LITERAL 0", push 0 to stack
+ SET_HEALTH(2), // e.g. "SET_HEALTH", pop health and wizard number, call set health
+ SET_WISDOM(3), // e.g. "SET_WISDOM", pop wisdom and wizard number, call set wisdom
+ SET_AGILITY(4), // e.g. "SET_AGILITY", pop agility and wizard number, call set agility
+ PLAY_SOUND(5), // e.g. "PLAY_SOUND", pop value as wizard number, call play sound
+ SPAWN_PARTICLES(6), // e.g. "SPAWN_PARTICLES", pop value as wizard number, call spawn particles
+ GET_HEALTH(7), // e.g. "GET_HEALTH", pop value as wizard number, push wizard's health
+ GET_AGILITY(8), // e.g. "GET_AGILITY", pop value as wizard number, push wizard's agility
+ GET_WISDOM(9), // e.g. "GET_WISDOM", pop value as wizard number, push wizard's wisdom
+ ADD(10), // e.g. "ADD", pop 2 values, push their sum
+ DIVIDE(11); // e.g. "DIVIDE", pop 2 values, push their division
- private final int value;
-
- Instruction(int value) {
- this.value = value;
- }
-
- public int getIntValue() {
- return value;
- }
+ private final int intValue;
/**
* Converts integer value to Instruction.
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java b/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
index c45301c29..ee223b5d8 100644
--- a/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,10 +24,15 @@
package com.iluwatar.bytecode;
import java.util.Stack;
+import java.util.concurrent.ThreadLocalRandom;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
/**
* Implementation of virtual machine.
*/
+@Getter
+@Slf4j
public class VirtualMachine {
private final Stack stack = new Stack<>();
@@ -35,12 +40,21 @@ public class VirtualMachine {
private final Wizard[] wizards = new Wizard[2];
/**
- * Constructor.
+ * No-args constructor.
*/
public VirtualMachine() {
- for (var i = 0; i < wizards.length; i++) {
- wizards[i] = new Wizard();
- }
+ wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
+ 0, 0);
+ wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32),
+ 0, 0);
+ }
+
+ /**
+ * Constructor taking the wizards as arguments.
+ */
+ public VirtualMachine(Wizard wizard1, Wizard wizard2) {
+ wizards[0] = wizard1;
+ wizards[1] = wizard2;
}
/**
@@ -55,6 +69,7 @@ public class VirtualMachine {
case LITERAL:
// Read the next byte from the bytecode.
int value = bytecode[++i];
+ // Push the next value to stack
stack.push(value);
break;
case SET_AGILITY:
@@ -105,13 +120,10 @@ public class VirtualMachine {
default:
throw new IllegalArgumentException("Invalid instruction value");
}
+ LOGGER.info("Executed " + instruction.name() + ", Stack contains " + getStack());
}
}
- public Stack getStack() {
- return stack;
- }
-
public void setHealth(int wizard, int amount) {
wizards[wizard].setHealth(amount);
}
@@ -136,7 +148,7 @@ public class VirtualMachine {
return wizards[wizard].getAgility();
}
- public Wizard[] getWizards() {
- return wizards;
+ private int randomInt(int min, int max) {
+ return ThreadLocalRandom.current().nextInt(min, max + 1);
}
}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java b/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java
index 5153969d9..ce62b276a 100644
--- a/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,48 +23,27 @@
package com.iluwatar.bytecode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
/**
* This class represent game objects which properties can be changed by instructions interpreted by
* virtual machine.
*/
+@AllArgsConstructor
+@Setter
+@Getter
+@Slf4j
public class Wizard {
- private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
private int health;
-
private int agility;
private int wisdom;
-
private int numberOfPlayedSounds;
private int numberOfSpawnedParticles;
- public int getHealth() {
- return health;
- }
-
- public void setHealth(int health) {
- this.health = health;
- }
-
- public int getAgility() {
- return agility;
- }
-
- public void setAgility(int agility) {
- this.agility = agility;
- }
-
- public int getWisdom() {
- return wisdom;
- }
-
- public void setWisdom(int wisdom) {
- this.wisdom = wisdom;
- }
-
public void playSound() {
LOGGER.info("Playing sound");
numberOfPlayedSounds++;
@@ -74,12 +53,4 @@ public class Wizard {
LOGGER.info("Spawning particles");
numberOfSpawnedParticles++;
}
-
- public int getNumberOfPlayedSounds() {
- return numberOfPlayedSounds;
- }
-
- public int getNumberOfSpawnedParticles() {
- return numberOfSpawnedParticles;
- }
}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/util/InstructionConverterUtil.java b/bytecode/src/main/java/com/iluwatar/bytecode/util/InstructionConverterUtil.java
index b0baf326e..ab7643129 100644
--- a/bytecode/src/main/java/com/iluwatar/bytecode/util/InstructionConverterUtil.java
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/util/InstructionConverterUtil.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -73,6 +73,4 @@ public class InstructionConverterUtil {
return false;
}
}
-
-
}
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
index 59962d39e..a035c797e 100644
--- a/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,13 +25,22 @@ package com.iluwatar.bytecode;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Application test
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
index 4518ca310..1fbe72014 100644
--- a/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,19 +23,19 @@
package com.iluwatar.bytecode;
-import org.junit.jupiter.api.Test;
-
import static com.iluwatar.bytecode.Instruction.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.api.Test;
+
/**
- * Test for {@Link VirtualMachine}
+ * Test for {@link VirtualMachine}
*/
-public class VirtualMachineTest {
+class VirtualMachineTest {
@Test
- public void testLiteral() {
+ void testLiteral() {
var bytecode = new int[2];
bytecode[0] = LITERAL.getIntValue();
bytecode[1] = 10;
@@ -48,7 +48,7 @@ public class VirtualMachineTest {
}
@Test
- public void testSetHealth() {
+ void testSetHealth() {
var wizardNumber = 0;
var bytecode = new int[5];
bytecode[0] = LITERAL.getIntValue();
@@ -64,7 +64,7 @@ public class VirtualMachineTest {
}
@Test
- public void testSetAgility() {
+ void testSetAgility() {
var wizardNumber = 0;
var bytecode = new int[5];
bytecode[0] = LITERAL.getIntValue();
@@ -80,7 +80,7 @@ public class VirtualMachineTest {
}
@Test
- public void testSetWisdom() {
+ void testSetWisdom() {
var wizardNumber = 0;
var bytecode = new int[5];
bytecode[0] = LITERAL.getIntValue();
@@ -96,7 +96,7 @@ public class VirtualMachineTest {
}
@Test
- public void testGetHealth() {
+ void testGetHealth() {
var wizardNumber = 0;
var bytecode = new int[8];
bytecode[0] = LITERAL.getIntValue();
@@ -115,7 +115,7 @@ public class VirtualMachineTest {
}
@Test
- public void testPlaySound() {
+ void testPlaySound() {
var wizardNumber = 0;
var bytecode = new int[3];
bytecode[0] = LITERAL.getIntValue();
@@ -130,7 +130,7 @@ public class VirtualMachineTest {
}
@Test
- public void testSpawnParticles() {
+ void testSpawnParticles() {
var wizardNumber = 0;
var bytecode = new int[3];
bytecode[0] = LITERAL.getIntValue();
@@ -145,7 +145,7 @@ public class VirtualMachineTest {
}
@Test
- public void testInvalidInstruction() {
+ void testInvalidInstruction() {
var bytecode = new int[1];
bytecode[0] = 999;
var vm = new VirtualMachine();
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/util/InstructionConverterUtilTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/util/InstructionConverterUtilTest.java
index e7438fce1..89486a8f7 100644
--- a/bytecode/src/test/java/com/iluwatar/bytecode/util/InstructionConverterUtilTest.java
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/util/InstructionConverterUtilTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,16 +24,16 @@
package com.iluwatar.bytecode.util;
import com.iluwatar.bytecode.Instruction;
-import com.iluwatar.bytecode.util.InstructionConverterUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
- * Test for {@Link InstructionConverterUtil}
+ * Test for {@link InstructionConverterUtil}
*/
-public class InstructionConverterUtilTest {
+class InstructionConverterUtilTest {
+
@Test
- public void testEmptyInstruction() {
+ void testEmptyInstruction() {
var instruction = "";
var bytecode = InstructionConverterUtil.convertToByteCode(instruction);
@@ -42,7 +42,7 @@ public class InstructionConverterUtilTest {
}
@Test
- public void testInstructions() {
+ void testInstructions() {
var instructions = "LITERAL 35 SET_HEALTH SET_WISDOM SET_AGILITY PLAY_SOUND"
+ " SPAWN_PARTICLES GET_HEALTH ADD DIVIDE";
diff --git a/caching/README.md b/caching/README.md
index 912f1d218..89487fc42 100644
--- a/caching/README.md
+++ b/caching/README.md
@@ -10,20 +10,326 @@ tags:
---
## Intent
-To avoid expensive re-acquisition of resources by not releasing
-the resources immediately after their use. The resources retain their identity, are kept in some
-fast-access storage, and are re-used to avoid having to acquire them again.
+
+The caching pattern avoids expensive re-acquisition of resources by not releasing them immediately
+after use. The resources retain their identity, are kept in some fast-access storage, and are
+re-used to avoid having to acquire them again.
+
+## Explanation
+
+Real world example
+
+> A team is working on a website that provides new homes for abandoned cats. People can post their
+> cats on the website after registering, but all the new posts require approval from one of the
+> site moderators. The user accounts of the site moderators contain a specific flag and the data
+> is stored in a MongoDB database. Checking for the moderator flag each time a post is viewed
+> becomes expensive and it's a good idea to utilize caching here.
+
+In plain words
+
+> Caching pattern keeps frequently needed data in fast-access storage to improve performance.
+
+Wikipedia says:
+
+> In computing, a cache is a hardware or software component that stores data so that future
+> requests for that data can be served faster; the data stored in a cache might be the result of
+> an earlier computation or a copy of data stored elsewhere. A cache hit occurs when the requested
+> data can be found in a cache, while a cache miss occurs when it cannot. Cache hits are served by
+> reading data from the cache, which is faster than recomputing a result or reading from a slower
+> data store; thus, the more requests that can be served from the cache, the faster the system
+> performs.
+
+**Programmatic Example**
+
+Let's first look at the data layer of our application. The interesting classes are `UserAccount`
+which is a simple Java object containing the user account details, and `DbManager` which handles
+reading and writing of these objects to/from MongoDB database.
+
+```java
+@Setter
+@Getter
+@AllArgsConstructor
+@ToString
+public class UserAccount {
+ private String userId;
+ private String userName;
+ private String additionalInfo;
+}
+
+@Slf4j
+public final class DbManager {
+
+ private static MongoClient mongoClient;
+ private static MongoDatabase db;
+
+ private DbManager() { /*...*/ }
+
+ public static void createVirtualDb() { /*...*/ }
+
+ public static void connect() throws ParseException { /*...*/ }
+
+ public static UserAccount readFromDb(String userId) { /*...*/ }
+
+ public static void writeToDb(UserAccount userAccount) { /*...*/ }
+
+ public static void updateDb(UserAccount userAccount) { /*...*/ }
+
+ public static void upsertDb(UserAccount userAccount) { /*...*/ }
+}
+```
+
+In the example, we are demonstrating various different caching policies
+
+* Write-through writes data to the cache and DB in a single transaction
+* Write-around writes data immediately into the DB instead of the cache
+* Write-behind writes data into the cache initially whilst the data is only written into the DB
+ when the cache is full
+* Cache-aside pushes the responsibility of keeping the data synchronized in both data sources to
+ the application itself
+* Read-through strategy is also included in the aforementioned strategies and it returns data from
+ the cache to the caller if it exists, otherwise queries from DB and stores it into the cache for
+ future use.
+
+The cache implementation in `LruCache` is a hash table accompanied by a doubly
+linked-list. The linked-list helps in capturing and maintaining the LRU data in the cache. When
+data is queried (from the cache), added (to the cache), or updated, the data is moved to the front
+of the list to depict itself as the most-recently-used data. The LRU data is always at the end of
+the list.
+
+```java
+@Slf4j
+public class LruCache {
+
+ static class Node {
+ String userId;
+ UserAccount userAccount;
+ Node previous;
+ Node next;
+
+ public Node(String userId, UserAccount userAccount) {
+ this.userId = userId;
+ this.userAccount = userAccount;
+ }
+ }
+
+ /* ... omitted details ... */
+
+ public LruCache(int capacity) {
+ this.capacity = capacity;
+ }
+
+ public UserAccount get(String userId) {
+ if (cache.containsKey(userId)) {
+ var node = cache.get(userId);
+ remove(node);
+ setHead(node);
+ return node.userAccount;
+ }
+ return null;
+ }
+
+ public void set(String userId, UserAccount userAccount) {
+ if (cache.containsKey(userId)) {
+ var old = cache.get(userId);
+ old.userAccount = userAccount;
+ remove(old);
+ setHead(old);
+ } else {
+ var newNode = new Node(userId, userAccount);
+ if (cache.size() >= capacity) {
+ LOGGER.info("# Cache is FULL! Removing {} from cache...", end.userId);
+ cache.remove(end.userId); // remove LRU data from cache.
+ remove(end);
+ setHead(newNode);
+ } else {
+ setHead(newNode);
+ }
+ cache.put(userId, newNode);
+ }
+ }
+
+ public boolean contains(String userId) {
+ return cache.containsKey(userId);
+ }
+
+ public void remove(Node node) { /* ... */ }
+ public void setHead(Node node) { /* ... */ }
+ public void invalidate(String userId) { /* ... */ }
+ public boolean isFull() { /* ... */ }
+ public UserAccount getLruData() { /* ... */ }
+ public void clear() { /* ... */ }
+ public List getCacheDataInListForm() { /* ... */ }
+ public void setCapacity(int newCapacity) { /* ... */ }
+}
+```
+
+The next layer we are going to look at is `CacheStore` which implements the different caching
+strategies.
+
+```java
+@Slf4j
+public class CacheStore {
+
+ private static LruCache cache;
+
+ /* ... details omitted ... */
+
+ public static UserAccount readThrough(String userId) {
+ if (cache.contains(userId)) {
+ LOGGER.info("# Cache Hit!");
+ return cache.get(userId);
+ }
+ LOGGER.info("# Cache Miss!");
+ UserAccount userAccount = DbManager.readFromDb(userId);
+ cache.set(userId, userAccount);
+ return userAccount;
+ }
+
+ public static void writeThrough(UserAccount userAccount) {
+ if (cache.contains(userAccount.getUserId())) {
+ DbManager.updateDb(userAccount);
+ } else {
+ DbManager.writeToDb(userAccount);
+ }
+ cache.set(userAccount.getUserId(), userAccount);
+ }
+
+ public static void clearCache() {
+ if (cache != null) {
+ cache.clear();
+ }
+ }
+
+ public static void flushCache() {
+ LOGGER.info("# flushCache...");
+ Optional.ofNullable(cache)
+ .map(LruCache::getCacheDataInListForm)
+ .orElse(List.of())
+ .forEach(DbManager::updateDb);
+ }
+
+ /* ... omitted the implementation of other caching strategies ... */
+
+}
+```
+
+`AppManager` helps to bridge the gap in communication between the main class and the application's
+back-end. DB connection is initialized through this class. The chosen caching strategy/policy is
+also initialized here. Before the cache can be used, the size of the cache has to be set. Depending
+on the chosen caching policy, `AppManager` will call the appropriate function in the `CacheStore`
+class.
+
+```java
+@Slf4j
+public final class AppManager {
+
+ private static CachingPolicy cachingPolicy;
+
+ private AppManager() {
+ }
+
+ public static void initDb(boolean useMongoDb) { /* ... */ }
+
+ public static void initCachingPolicy(CachingPolicy policy) { /* ... */ }
+
+ public static void initCacheCapacity(int capacity) { /* ... */ }
+
+ public static UserAccount find(String userId) {
+ if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) {
+ return CacheStore.readThrough(userId);
+ } else if (cachingPolicy == CachingPolicy.BEHIND) {
+ return CacheStore.readThroughWithWriteBackPolicy(userId);
+ } else if (cachingPolicy == CachingPolicy.ASIDE) {
+ return findAside(userId);
+ }
+ return null;
+ }
+
+ public static void save(UserAccount userAccount) {
+ if (cachingPolicy == CachingPolicy.THROUGH) {
+ CacheStore.writeThrough(userAccount);
+ } else if (cachingPolicy == CachingPolicy.AROUND) {
+ CacheStore.writeAround(userAccount);
+ } else if (cachingPolicy == CachingPolicy.BEHIND) {
+ CacheStore.writeBehind(userAccount);
+ } else if (cachingPolicy == CachingPolicy.ASIDE) {
+ saveAside(userAccount);
+ }
+ }
+
+ public static String printCacheContent() {
+ return CacheStore.print();
+ }
+
+ /* ... details omitted ... */
+}
+```
+
+Here is what we do in the main class of the application.
+
+```java
+@Slf4j
+public class App {
+
+ public static void main(String[] args) {
+ AppManager.initDb(false);
+ AppManager.initCacheCapacity(3);
+ var app = new App();
+ app.useReadAndWriteThroughStrategy();
+ app.useReadThroughAndWriteAroundStrategy();
+ app.useReadThroughAndWriteBehindStrategy();
+ app.useCacheAsideStategy();
+ }
+
+ public void useReadAndWriteThroughStrategy() {
+ LOGGER.info("# CachingPolicy.THROUGH");
+ AppManager.initCachingPolicy(CachingPolicy.THROUGH);
+ var userAccount1 = new UserAccount("001", "John", "He is a boy.");
+ AppManager.save(userAccount1);
+ LOGGER.info(AppManager.printCacheContent());
+ AppManager.find("001");
+ AppManager.find("001");
+ }
+
+ public void useReadThroughAndWriteAroundStrategy() { /* ... */ }
+
+ public void useReadThroughAndWriteBehindStrategy() { /* ... */ }
+
+ public void useCacheAsideStategy() { /* ... */ }
+}
+```
+
+Finally, here is some of the console output from the program.
+
+```
+12:32:53.845 [main] INFO com.iluwatar.caching.App - # CachingPolicy.THROUGH
+12:32:53.900 [main] INFO com.iluwatar.caching.App -
+--CACHE CONTENT--
+UserAccount(userId=001, userName=John, additionalInfo=He is a boy.)
+----
+```
## Class diagram
+

## Applicability
+
Use the Caching pattern(s) when
-* Repetitious acquisition, initialization, and release of the same resource causes unnecessary performance overhead.
+* Repetitious acquisition, initialization, and release of the same resource cause unnecessary
+ performance overhead.
+
+## Related patterns
+
+* [Proxy](https://java-design-patterns.com/patterns/proxy/)
## Credits
* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
+* [Java EE 8 High Performance: Master techniques such as memory optimization, caching, concurrency, and multithreading to achieve maximum performance from your enterprise applications](https://www.amazon.com/gp/product/178847306X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=178847306X&linkId=e948720055599f248cdac47da9125ff4)
+* [Java Performance: In-Depth Advice for Tuning and Programming Java 8, 11, and Beyond](https://www.amazon.com/gp/product/1492056111/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1492056111&linkId=7e553581559b9ec04221259e52004b08)
+* [Effective Java](https://www.amazon.com/gp/product/B078H61SCH/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B078H61SCH&linkId=f06607a0b48c76541ef19c5b8b9e7882)
+* [Java Performance: The Definitive Guide: Getting the Most Out of Your Code](https://www.amazon.com/gp/product/1449358454/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1449358454&linkId=475c18363e350630cc0b39ab681b2687)
diff --git a/caching/pom.xml b/caching/pom.xml
index 704dd78d0..f15334c88 100644
--- a/caching/pom.xml
+++ b/caching/pom.xml
@@ -2,7 +2,7 @@
"-state" State
+DefaultCircuitBreaker --> "-state" State
+MonitoringService --> "-delayedService" CircuitBreaker
+DefaultCircuitBreaker --> "-service" RemoteService
+DefaultCircuitBreaker ..|> CircuitBreaker
+DelayedRemoteService ..|> RemoteService
+QuickRemoteService ..|> RemoteService
@enduml
\ No newline at end of file
diff --git a/circuit-breaker/pom.xml b/circuit-breaker/pom.xml
index fd9f85675..160537144 100644
--- a/circuit-breaker/pom.xml
+++ b/circuit-breaker/pom.xml
@@ -1,7 +1,7 @@
"-size" Size
-Wizard --> "-undoStack" Command
-ShrinkSpell --> "-oldSize" Size
-InvisibilitySpell --> "-target" Target
-ShrinkSpell --> "-target" Target
+Wizard --> "-changeSize" Goblin
+Wizard --> "-changeVisibility" Goblin
Target --> "-visibility" Visibility
Goblin --|> Target
-InvisibilitySpell ..|> Command
-ShrinkSpell ..|> Command
+App --> "castSpell" Wizard
@enduml
diff --git a/command/pom.xml b/command/pom.xml
index 50a14c45f..c0bc15810 100644
--- a/command/pom.xml
+++ b/command/pom.xml
@@ -2,7 +2,7 @@
+
java-design-patterns
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
converter
4.0.0
diff --git a/converter/src/main/java/com/iluwatar/converter/App.java b/converter/src/main/java/com/iluwatar/converter/App.java
index 2d4ec0429..dc3eab53a 100644
--- a/converter/src/main/java/com/iluwatar/converter/App.java
+++ b/converter/src/main/java/com/iluwatar/converter/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -24,8 +24,7 @@
package com.iluwatar.converter;
import java.util.List;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* The Converter pattern is a behavioral design pattern which allows a common way of bidirectional
@@ -33,10 +32,9 @@ import org.slf4j.LoggerFactory;
* isomorphic types). Moreover, the pattern introduces a common way of converting a collection of
* objects between types.
*/
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
-
/**
* Program entry point.
*
@@ -47,7 +45,7 @@ public class App {
UserDto dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com");
User user = userConverter.convertFromDto(dtoUser);
- LOGGER.info("Entity converted from DTO:" + user);
+ LOGGER.info("Entity converted from DTO: {}", user);
var users = List.of(
new User("Camile", "Tough", false, "124sad"),
diff --git a/converter/src/main/java/com/iluwatar/converter/Converter.java b/converter/src/main/java/com/iluwatar/converter/Converter.java
index 10425e1ca..a40650faf 100644
--- a/converter/src/main/java/com/iluwatar/converter/Converter.java
+++ b/converter/src/main/java/com/iluwatar/converter/Converter.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -27,6 +27,7 @@ import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
/**
* Generic converter, thanks to Java8 features not only provides a way of generic bidirectional
@@ -36,22 +37,12 @@ import java.util.stream.Collectors;
* @param DTO representation's type
* @param Domain representation's type
*/
+@RequiredArgsConstructor
public class Converter {
private final Function fromDto;
private final Function fromEntity;
- /**
- * Constructor.
- *
- * @param fromDto Function that converts given dto entity into the domain entity.
- * @param fromEntity Function that converts given domain entity into the dto entity.
- */
- public Converter(final Function fromDto, final Function fromEntity) {
- this.fromDto = fromDto;
- this.fromEntity = fromEntity;
- }
-
/**
* Converts DTO to Entity.
*
diff --git a/converter/src/main/java/com/iluwatar/converter/User.java b/converter/src/main/java/com/iluwatar/converter/User.java
index 2c1ba9ff0..f8b528a56 100644
--- a/converter/src/main/java/com/iluwatar/converter/User.java
+++ b/converter/src/main/java/com/iluwatar/converter/User.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,69 +23,21 @@
package com.iluwatar.converter;
-import java.util.Objects;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
/**
* User class.
*/
+@ToString
+@EqualsAndHashCode
+@Getter
+@RequiredArgsConstructor
public class User {
private final String firstName;
private final String lastName;
- private final boolean isActive;
+ private final boolean active;
private final String userId;
-
- /**
- * Constructor.
- *
- * @param firstName user's first name
- * @param lastName user's last name
- * @param isActive flag indicating whether the user is active
- * @param userId user's identificator
- */
- public User(String firstName, String lastName, boolean isActive, String userId) {
- this.firstName = firstName;
- this.lastName = lastName;
- this.isActive = isActive;
- this.userId = userId;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public boolean isActive() {
- return isActive;
- }
-
- public String getUserId() {
- return userId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- var user = (User) o;
- return isActive == user.isActive && Objects.equals(firstName, user.firstName) && Objects
- .equals(lastName, user.lastName) && Objects.equals(userId, user.userId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(firstName, lastName, isActive, userId);
- }
-
- @Override
- public String toString() {
- return "User{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\''
- + ", isActive=" + isActive + ", userId='" + userId + '\'' + '}';
- }
}
diff --git a/converter/src/main/java/com/iluwatar/converter/UserConverter.java b/converter/src/main/java/com/iluwatar/converter/UserConverter.java
index c2341695e..7f5cabd82 100644
--- a/converter/src/main/java/com/iluwatar/converter/UserConverter.java
+++ b/converter/src/main/java/com/iluwatar/converter/UserConverter.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/converter/src/main/java/com/iluwatar/converter/UserDto.java b/converter/src/main/java/com/iluwatar/converter/UserDto.java
index 67a886087..0717c4952 100644
--- a/converter/src/main/java/com/iluwatar/converter/UserDto.java
+++ b/converter/src/main/java/com/iluwatar/converter/UserDto.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,70 +23,23 @@
package com.iluwatar.converter;
-import java.util.Objects;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
/**
* User DTO class.
*/
+@RequiredArgsConstructor
+@Getter
+@EqualsAndHashCode
+@ToString
public class UserDto {
private final String firstName;
private final String lastName;
- private final boolean isActive;
+ private final boolean active;
private final String email;
- /**
- * Constructor.
- *
- * @param firstName user's first name
- * @param lastName user's last name
- * @param isActive flag indicating whether the user is active
- * @param email user's email address
- */
- public UserDto(String firstName, String lastName, boolean isActive, String email) {
- this.firstName = firstName;
- this.lastName = lastName;
- this.isActive = isActive;
- this.email = email;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public boolean isActive() {
- return isActive;
- }
-
- public String getEmail() {
- return email;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- var userDto = (UserDto) o;
- return isActive == userDto.isActive && Objects.equals(firstName, userDto.firstName) && Objects
- .equals(lastName, userDto.lastName) && Objects.equals(email, userDto.email);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(firstName, lastName, isActive, email);
- }
-
- @Override
- public String toString() {
- return "UserDto{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\''
- + ", isActive=" + isActive + ", email='" + email + '\'' + '}';
- }
}
diff --git a/converter/src/test/java/com/iluwatar/converter/AppTest.java b/converter/src/test/java/com/iluwatar/converter/AppTest.java
index ed53c6863..55b9a2258 100644
--- a/converter/src/test/java/com/iluwatar/converter/AppTest.java
+++ b/converter/src/test/java/com/iluwatar/converter/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,14 +25,24 @@ package com.iluwatar.converter;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* App running test
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App#main(String[])}
+ * throws an exception.
+ */
@Test
- public void testMain() {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java
index 46aca82a7..d7358d8a4 100644
--- a/converter/src/test/java/com/iluwatar/converter/ConverterTest.java
+++ b/converter/src/test/java/com/iluwatar/converter/ConverterTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -32,7 +32,7 @@ import org.junit.jupiter.api.Test;
/**
* Tests for {@link Converter}
*/
-public class ConverterTest {
+class ConverterTest {
private final UserConverter userConverter = new UserConverter();
@@ -40,7 +40,7 @@ public class ConverterTest {
* Tests whether a converter created of opposite functions holds equality as a bijection.
*/
@Test
- public void testConversionsStartingFromDomain() {
+ void testConversionsStartingFromDomain() {
var u1 = new User("Tom", "Hanks", true, "tom@hanks.com");
var u2 = userConverter.convertFromDto(userConverter.convertFromEntity(u1));
assertEquals(u1, u2);
@@ -50,7 +50,7 @@ public class ConverterTest {
* Tests whether a converter created of opposite functions holds equality as a bijection.
*/
@Test
- public void testConversionsStartingFromDto() {
+ void testConversionsStartingFromDto() {
var u1 = new UserDto("Tom", "Hanks", true, "tom@hanks.com");
var u2 = userConverter.convertFromEntity(userConverter.convertFromDto(u1));
assertEquals(u1, u2);
@@ -61,7 +61,7 @@ public class ConverterTest {
* instantiated allowing various different conversion strategies to be implemented.
*/
@Test
- public void testCustomConverter() {
+ void testCustomConverter() {
var converter = new Converter(
userDto -> new User(
userDto.getFirstName(),
@@ -85,7 +85,7 @@ public class ConverterTest {
* domain users returns an equal collection.
*/
@Test
- public void testCollectionConversion() {
+ void testCollectionConversion() {
var users = List.of(
new User("Camile", "Tough", false, "124sad"),
new User("Marti", "Luther", true, "42309fd"),
diff --git a/cqrs/pom.xml b/cqrs/pom.xml
index b3a0303e6..7d2d5aca9 100644
--- a/cqrs/pom.xml
+++ b/cqrs/pom.xml
@@ -2,7 +2,7 @@
-
- com.github.sbrannen
- spring-test-junit5
- test
-
org.junit.jupiter
junit-jupiter-engine
diff --git a/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/App.java b/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/App.java
index 34fa6e307..d2ac10912 100644
--- a/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/App.java
+++ b/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/AggregatorRoute.java b/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/AggregatorRoute.java
index 2465fd960..ae0880c90 100644
--- a/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/AggregatorRoute.java
+++ b/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/AggregatorRoute.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategy.java b/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategy.java
index 9fd4c933a..365a0b45a 100644
--- a/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategy.java
+++ b/eip-aggregator/src/main/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategy.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/eip-aggregator/src/main/resources/application.properties b/eip-aggregator/src/main/resources/application.properties
index 34febce1a..ca07b459e 100644
--- a/eip-aggregator/src/main/resources/application.properties
+++ b/eip-aggregator/src/main/resources/application.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
diff --git a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java
index ed604e8c2..08e03441c 100644
--- a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java
+++ b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,13 +25,22 @@ package com.iluwatar.eip.aggregator;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Test for App class
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App#main(String[])}
+ * throws an exception.
+ */
@Test
- public void testMain() throws Exception {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/AggregatorRouteTest.java b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/AggregatorRouteTest.java
index e1c6f5b2b..305201694 100644
--- a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/AggregatorRouteTest.java
+++ b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/AggregatorRouteTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -49,7 +49,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
@ActiveProfiles("test")
@EnableAutoConfiguration
@ComponentScan
-public class AggregatorRouteTest {
+class AggregatorRouteTest {
@EndpointInject(uri = "{{entry}}")
private ProducerTemplate entry;
@@ -64,7 +64,7 @@ public class AggregatorRouteTest {
*/
@Test
@DirtiesContext
- public void testSplitter() throws Exception {
+ void testSplitter() throws Exception {
// Three items in one entry message
entry.sendBody("TEST1");
diff --git a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategyTest.java b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategyTest.java
index 8325e7255..40c15b370 100644
--- a/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategyTest.java
+++ b/eip-aggregator/src/test/java/com/iluwatar/eip/aggregator/routes/MessageAggregationStrategyTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -32,10 +32,10 @@ import org.junit.jupiter.api.Test;
/**
* Tests MessageAggregationStrategy
*/
-public class MessageAggregationStrategyTest {
+class MessageAggregationStrategyTest {
@Test
- public void testAggregate() {
+ void testAggregate() {
var mas = new MessageAggregationStrategy();
var oldExchange = new DefaultExchange((CamelContext) null);
oldExchange.getIn().setBody("TEST1");
@@ -49,7 +49,7 @@ public class MessageAggregationStrategyTest {
}
@Test
- public void testAggregateOldNull() {
+ void testAggregateOldNull() {
var mas = new MessageAggregationStrategy();
var newExchange = new DefaultExchange((CamelContext) null);
diff --git a/eip-aggregator/src/test/resources/application-test.properties b/eip-aggregator/src/test/resources/application-test.properties
index 0cab1156b..843005704 100644
--- a/eip-aggregator/src/test/resources/application-test.properties
+++ b/eip-aggregator/src/test/resources/application-test.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
diff --git a/eip-message-channel/pom.xml b/eip-message-channel/pom.xml
index bea72b1f9..33ee56c05 100644
--- a/eip-message-channel/pom.xml
+++ b/eip-message-channel/pom.xml
@@ -2,7 +2,7 @@
-
- com.github.sbrannen
- spring-test-junit5
- test
-
org.junit.jupiter
junit-jupiter-engine
diff --git a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java
index 2792e0be4..263d9fab5 100644
--- a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java
+++ b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java
index 4d2cb3efb..4fc467960 100644
--- a/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java
+++ b/eip-splitter/src/main/java/com/iluwatar/eip/splitter/routes/SplitterRoute.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/eip-splitter/src/main/resources/application.properties b/eip-splitter/src/main/resources/application.properties
index 34febce1a..ca07b459e 100644
--- a/eip-splitter/src/main/resources/application.properties
+++ b/eip-splitter/src/main/resources/application.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
diff --git a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java
index 1a7dfcb0a..c9ba7d17b 100644
--- a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java
+++ b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,13 +25,22 @@ package com.iluwatar.eip.splitter;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Test for App class
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App#main(String[])}
+ * throws an exception.
+ */
@Test
- public void testMain() throws Exception {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java
index 037954609..bc48e9ab4 100644
--- a/eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java
+++ b/eip-splitter/src/test/java/com/iluwatar/eip/splitter/routes/SplitterRouteTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -47,7 +47,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
@ActiveProfiles("test")
@EnableAutoConfiguration
@ComponentScan
-public class SplitterRouteTest {
+class SplitterRouteTest {
@EndpointInject(uri = "{{entry}}")
private ProducerTemplate entry;
@@ -62,7 +62,7 @@ public class SplitterRouteTest {
*/
@Test
@DirtiesContext
- public void testSplitter() throws Exception {
+ void testSplitter() throws Exception {
// Three items in one entry message
entry.sendBody(new String[]{"TEST1", "TEST2", "TEST3"});
diff --git a/eip-splitter/src/test/resources/application-test.properties b/eip-splitter/src/test/resources/application-test.properties
index 0cab1156b..843005704 100644
--- a/eip-splitter/src/test/resources/application-test.properties
+++ b/eip-splitter/src/test/resources/application-test.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
diff --git a/eip-wire-tap/pom.xml b/eip-wire-tap/pom.xml
index 06cbc33db..d7c2d1568 100644
--- a/eip-wire-tap/pom.xml
+++ b/eip-wire-tap/pom.xml
@@ -2,7 +2,7 @@
-
- com.github.sbrannen
- spring-test-junit5
- test
-
org.junit.jupiter
junit-jupiter-engine
diff --git a/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/App.java b/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/App.java
index f3b5c11c1..7940d3e5e 100644
--- a/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/App.java
+++ b/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/routes/WireTapRoute.java b/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/routes/WireTapRoute.java
index 8eea7adbd..39d89e738 100644
--- a/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/routes/WireTapRoute.java
+++ b/eip-wire-tap/src/main/java/com/iluwatar/eip/wiretap/routes/WireTapRoute.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
diff --git a/eip-wire-tap/src/main/resources/application.properties b/eip-wire-tap/src/main/resources/application.properties
index 13e13b959..cb77786ed 100644
--- a/eip-wire-tap/src/main/resources/application.properties
+++ b/eip-wire-tap/src/main/resources/application.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
diff --git a/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java b/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java
index 31154043c..20fc2a8bc 100644
--- a/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java
+++ b/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -25,13 +25,22 @@ package com.iluwatar.eip.wiretap;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
/**
* Test for App class
*/
-public class AppTest {
+class AppTest {
+
+ /**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App#main(String[])}
+ * throws an exception.
+ */
@Test
- public void testMain() throws Exception {
- App.main(new String[]{});
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/routes/WireTapRouteTest.java b/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/routes/WireTapRouteTest.java
index 0d13374dc..49bb043c4 100644
--- a/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/routes/WireTapRouteTest.java
+++ b/eip-wire-tap/src/test/java/com/iluwatar/eip/wiretap/routes/WireTapRouteTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -49,7 +49,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
@ActiveProfiles("test")
@EnableAutoConfiguration
@ComponentScan
-public class WireTapRouteTest {
+class WireTapRouteTest {
@EndpointInject(uri = "{{entry}}")
private ProducerTemplate entry;
@@ -67,7 +67,7 @@ public class WireTapRouteTest {
*/
@Test
@DirtiesContext
- public void testWireTap() throws Exception {
+ void testWireTap() throws Exception {
entry.sendBody("TEST");
endpoint.expectedMessageCount(1);
diff --git a/eip-wire-tap/src/test/resources/application-test.properties b/eip-wire-tap/src/test/resources/application-test.properties
index a64f4b316..801b7c928 100644
--- a/eip-wire-tap/src/test/resources/application-test.properties
+++ b/eip-wire-tap/src/test/resources/application-test.properties
@@ -1,6 +1,6 @@
#
# The MIT License
-# Copyright © 2014-2019 Ilkka Seppälä
+# Copyright © 2014-2021 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
diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml
index 5553de2e3..e9b712f37 100644
--- a/event-aggregator/pom.xml
+++ b/event-aggregator/pom.xml
@@ -1,7 +1,7 @@
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.24.0-SNAPSHOT
+
+ factory
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.factory.App
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mutex/src/main/java/com/iluwatar/mutex/App.java b/factory/src/main/java/com/iluwatar/factory/App.java
similarity index 58%
rename from mutex/src/main/java/com/iluwatar/mutex/App.java
rename to factory/src/main/java/com/iluwatar/factory/App.java
index c50acc65a..732f5458f 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/App.java
+++ b/factory/src/main/java/com/iluwatar/factory/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,29 +21,29 @@
* THE SOFTWARE.
*/
-package com.iluwatar.mutex;
+package com.iluwatar.factory;
+
+import lombok.extern.slf4j.Slf4j;
/**
- * A Mutex prevents multiple threads from accessing a resource simultaneously.
+ * Factory is an object for creating other objects, it providing Providing a static method to
+ * create and return objects of varying classes, in order to hide the implementation logic
+ * and makes client code focus on usage rather then objects initialization and management.
*
- * In this example we have two thieves who are taking beans from a jar. Only one thief can take
- * a bean at a time. This is ensured by a Mutex lock which must be acquired in order to access the
- * jar. Each thief attempts to acquire the lock, take a bean and then release the lock. If the lock
- * has already been acquired, the thief will be prevented from continuing (blocked) until the lock
- * has been released. The thieves stop taking beans once there are no beans left to take.
+ *
In this example the CarFactory is the factory class and it provides a static method to
+ * create different cars.
*/
+
+@Slf4j
public class App {
/**
- * main method.
+ * Program main entry point.
*/
public static void main(String[] args) {
- 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();
+ var car1 = CarsFactory.getCar(CarType.FORD);
+ var car2 = CarsFactory.getCar(CarType.FERRARI);
+ LOGGER.info(car1.getDescription());
+ LOGGER.info(car2.getDescription());
}
-
}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java b/factory/src/main/java/com/iluwatar/factory/Car.java
similarity index 87%
rename from business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java
rename to factory/src/main/java/com/iluwatar/factory/Car.java
index c0f02b5e3..e1e248fb4 100644
--- a/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java
+++ b/factory/src/main/java/com/iluwatar/factory/Car.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,12 +21,13 @@
* THE SOFTWARE.
*/
-package com.iluwatar.business.delegate;
+package com.iluwatar.factory;
/**
- * Enumeration for service types.
+ * Car interface.
*/
-public enum ServiceType {
+public interface Car {
+
+ String getDescription();
- EJB, JMS
}
diff --git a/factory/src/main/java/com/iluwatar/factory/CarType.java b/factory/src/main/java/com/iluwatar/factory/CarType.java
new file mode 100644
index 000000000..074ea32bc
--- /dev/null
+++ b/factory/src/main/java/com/iluwatar/factory/CarType.java
@@ -0,0 +1,42 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.factory;
+
+import java.util.function.Supplier;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Enumeration for different types of cars.
+ */
+@RequiredArgsConstructor
+@Getter
+public enum CarType {
+
+ FORD(Ford::new),
+ FERRARI(Ferrari::new);
+
+ private final Supplier constructor;
+
+}
diff --git a/factory/src/main/java/com/iluwatar/factory/CarsFactory.java b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java
new file mode 100644
index 000000000..941552065
--- /dev/null
+++ b/factory/src/main/java/com/iluwatar/factory/CarsFactory.java
@@ -0,0 +1,37 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.factory;
+
+/**
+ * Factory of cars.
+ */
+public class CarsFactory {
+
+ /**
+ * Factory method takes as parameter a car type and initiate the appropriate class.
+ */
+ public static Car getCar(CarType type) {
+ return type.getConstructor().get();
+ }
+}
diff --git a/factory/src/main/java/com/iluwatar/factory/Ferrari.java b/factory/src/main/java/com/iluwatar/factory/Ferrari.java
new file mode 100644
index 000000000..c11ee3679
--- /dev/null
+++ b/factory/src/main/java/com/iluwatar/factory/Ferrari.java
@@ -0,0 +1,37 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.factory;
+
+/**
+ * Ferrari implementation.
+ */
+public class Ferrari implements Car {
+
+ static final String DESCRIPTION = "This is Ferrari.";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/Lock.java b/factory/src/main/java/com/iluwatar/factory/Ford.java
similarity index 81%
rename from semaphore/src/main/java/com/iluwatar/semaphore/Lock.java
rename to factory/src/main/java/com/iluwatar/factory/Ford.java
index 5679e2a05..d1091a00b 100644
--- a/semaphore/src/main/java/com/iluwatar/semaphore/Lock.java
+++ b/factory/src/main/java/com/iluwatar/factory/Ford.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,15 +21,17 @@
* THE SOFTWARE.
*/
-package com.iluwatar.semaphore;
+package com.iluwatar.factory;
/**
- * Lock is an interface for a lock which can be acquired and released.
+ * Ford implementation.
*/
-public interface Lock {
+public class Ford implements Car {
- void acquire() throws InterruptedException;
-
- void release();
+ static final String DESCRIPTION = "This is Ford.";
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
}
diff --git a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java b/factory/src/test/java/com/iluwatar/factory/AppTest.java
similarity index 82%
rename from semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java
rename to factory/src/test/java/com/iluwatar/factory/AppTest.java
index f450c0593..9bb244500 100644
--- a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java
+++ b/factory/src/test/java/com/iluwatar/factory/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,16 +21,17 @@
* THE SOFTWARE.
*/
-package com.iluwatar.semaphore;
+package com.iluwatar.factory;
+
+import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
-/**
- * Application Test Entrypoint
- */
-public class AppTest {
+class AppTest {
+
@Test
- public void test() {
- App.main(new String[]{});
+ void shouldExecuteWithoutExceptions() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
+
}
diff --git a/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java
new file mode 100644
index 000000000..c29cbbeb4
--- /dev/null
+++ b/factory/src/test/java/com/iluwatar/factory/CarsFactoryTest.java
@@ -0,0 +1,38 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.factory;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class CarsFactoryTest {
+
+ @Test
+ void shouldReturnFerrariInstance() {
+ final var ferrari = CarsFactory.getCar(CarType.FERRARI);
+ assertTrue(ferrari instanceof Ferrari);
+ }
+
+}
diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml
index 13f646b80..b20d05afa 100644
--- a/feature-toggle/pom.xml
+++ b/feature-toggle/pom.xml
@@ -2,7 +2,7 @@
"-issues" Threat
+SimpleThreat --> "-threatType" ThreatType
+SimpleProbabilisticThreatAwareSystem --> "-threats" ProbableThreat
+ProbabilisticThreatAwareSystem --|> ThreatAwareSystem
+ProbableThreat --|> Threat
+SimpleProbabilisticThreatAwareSystem ..|> ProbabilisticThreatAwareSystem
+SimpleProbableThreat ..|> ProbableThreat
+SimpleProbableThreat --|> SimpleThreat
+SimpleThreat ..|> Threat
+SimpleThreatAwareSystem ..|> ThreatAwareSystem
+@enduml
\ No newline at end of file
diff --git a/filterer/pom.xml b/filterer/pom.xml
new file mode 100644
index 000000000..19500b859
--- /dev/null
+++ b/filterer/pom.xml
@@ -0,0 +1,73 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.24.0-SNAPSHOT
+
+ 4.0.0
+
+ filterer
+
+
+
+ com.google.guava
+ guava
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.filterer.App
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/filterer/src/main/java/com/iluwatar/filterer/App.java b/filterer/src/main/java/com/iluwatar/filterer/App.java
new file mode 100644
index 000000000..d25c73a55
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/App.java
@@ -0,0 +1,104 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer;
+
+import com.iluwatar.filterer.threat.ProbableThreat;
+import com.iluwatar.filterer.threat.SimpleProbabilisticThreatAwareSystem;
+import com.iluwatar.filterer.threat.SimpleProbableThreat;
+import com.iluwatar.filterer.threat.SimpleThreat;
+import com.iluwatar.filterer.threat.SimpleThreatAwareSystem;
+import com.iluwatar.filterer.threat.Threat;
+import com.iluwatar.filterer.threat.ThreatAwareSystem;
+import com.iluwatar.filterer.threat.ThreatType;
+import java.util.List;
+import java.util.function.Predicate;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * This demo class represent how {@link com.iluwatar.filterer.domain.Filterer} pattern is used to
+ * filter container-like objects to return filtered versions of themselves. The container like
+ * objects are systems that are aware of threats that they can be vulnerable to. We would like
+ * to have a way to create copy of different system objects but with filtered threats.
+ * The thing is to keep it simple if we add new subtype of {@link Threat}
+ * (for example {@link ProbableThreat}) - we still need to be able to filter by it's properties.
+ */
+@Slf4j
+public class App {
+
+ public static void main(String[] args) {
+ filteringSimpleThreats();
+ filteringSimpleProbableThreats();
+ }
+
+ /**
+ * Demonstrates how to filter {@link com.iluwatar.filterer.threat.ProbabilisticThreatAwareSystem}
+ * based on probability property. The @{@link com.iluwatar.filterer.domain.Filterer#by(Predicate)}
+ * method is able to use {@link com.iluwatar.filterer.threat.ProbableThreat}
+ * as predicate argument.
+ */
+ private static void filteringSimpleProbableThreats() {
+ LOGGER.info("### Filtering ProbabilisticThreatAwareSystem by probability ###");
+
+ var trojanArcBomb = new SimpleProbableThreat("Trojan-ArcBomb", 1, ThreatType.TROJAN, 0.99);
+ var rootkit = new SimpleProbableThreat("Rootkit-Kernel", 2, ThreatType.ROOTKIT, 0.8);
+
+ List probableThreats = List.of(trojanArcBomb, rootkit);
+
+ var probabilisticThreatAwareSystem =
+ new SimpleProbabilisticThreatAwareSystem("Sys-1", probableThreats);
+
+ LOGGER.info("Filtering ProbabilisticThreatAwareSystem. Initial : "
+ + probabilisticThreatAwareSystem);
+
+ //Filtering using filterer
+ var filteredThreatAwareSystem = probabilisticThreatAwareSystem.filtered()
+ .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0);
+
+ LOGGER.info("Filtered by probability = 0.99 : " + filteredThreatAwareSystem);
+ }
+
+ /**
+ * Demonstrates how to filter {@link ThreatAwareSystem} based on startingOffset property
+ * of {@link SimpleThreat}. The @{@link com.iluwatar.filterer.domain.Filterer#by(Predicate)}
+ * method is able to use {@link Threat} as predicate argument.
+ */
+ private static void filteringSimpleThreats() {
+ LOGGER.info("### Filtering ThreatAwareSystem by ThreatType ###");
+
+ var rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit");
+ var trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan");
+ List threats = List.of(rootkit, trojan);
+
+ var threatAwareSystem = new SimpleThreatAwareSystem("Sys-1", threats);
+
+ LOGGER.info("Filtering ThreatAwareSystem. Initial : " + threatAwareSystem);
+
+ //Filtering using Filterer
+ var rootkitThreatAwareSystem = threatAwareSystem.filtered()
+ .by(threat -> threat.type() == ThreatType.ROOTKIT);
+
+ LOGGER.info("Filtered by threatType = ROOTKIT : " + rootkitThreatAwareSystem);
+ }
+
+}
diff --git a/filterer/src/main/java/com/iluwatar/filterer/domain/Filterer.java b/filterer/src/main/java/com/iluwatar/filterer/domain/Filterer.java
new file mode 100644
index 000000000..a9d3f9dc6
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/domain/Filterer.java
@@ -0,0 +1,36 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.domain;
+
+import java.util.function.Predicate;
+
+/**
+ * Filterer helper interface.
+ * @param type of the container-like object.
+ * @param type of the elements contained within this container-like object.
+ */
+@FunctionalInterface
+public interface Filterer {
+ G by(Predicate super E> predicate);
+}
\ No newline at end of file
diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java
new file mode 100644
index 000000000..9d6a9ce5e
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java
@@ -0,0 +1,49 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+import com.iluwatar.filterer.domain.Filterer;
+
+import java.util.List;
+
+/**
+ * Represents system that is aware of it's threats with given probability of their occurrence.
+ */
+public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem {
+
+ /**
+ * {@inheritDoc}
+ * @return
+ */
+ @Override
+ List extends ProbableThreat> threats();
+
+ /**
+ * {@inheritDoc}
+ * @return
+ */
+ @Override
+ Filterer extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> filtered();
+}
+
diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java
new file mode 100644
index 000000000..dec119f84
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java
@@ -0,0 +1,35 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+/**
+ * Represents threat that might be a threat with given probability.
+ */
+public interface ProbableThreat extends Threat {
+ /**
+ * Returns probability of occurrence of given threat.
+ * @return probability of occurrence of given threat.
+ */
+ double probability();
+}
\ No newline at end of file
diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java
new file mode 100644
index 000000000..ac16e6614
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java
@@ -0,0 +1,81 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+import com.iluwatar.filterer.domain.Filterer;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+
+/**
+ * {@inheritDoc}
+ */
+@ToString
+@EqualsAndHashCode
+@RequiredArgsConstructor
+public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem {
+
+ private final String systemId;
+ private final List threats;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String systemId() {
+ return systemId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List extends ProbableThreat> threats() {
+ return threats;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Filterer extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> filtered() {
+ return this::filteredGroup;
+ }
+
+ private ProbabilisticThreatAwareSystem filteredGroup(
+ final Predicate super ProbableThreat> predicate) {
+ return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate));
+ }
+
+ private List filteredItems(
+ final Predicate super ProbableThreat> predicate) {
+ return this.threats.stream()
+ .filter(predicate)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+}
diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java
new file mode 100644
index 000000000..307e6d41b
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java
@@ -0,0 +1,57 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+import lombok.EqualsAndHashCode;
+
+/**
+ * {@inheritDoc}
+ */
+@EqualsAndHashCode(callSuper = false)
+public class SimpleProbableThreat extends SimpleThreat implements ProbableThreat {
+
+ private final double probability;
+
+ public SimpleProbableThreat(final String name, final int id, final ThreatType threatType,
+ final double probability) {
+ super(threatType, id, name);
+ this.probability = probability;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double probability() {
+ return probability;
+ }
+
+ @Override
+ public String toString() {
+ return "SimpleProbableThreat{"
+ + "probability=" + probability
+ + "} "
+ + super.toString();
+ }
+}
diff --git a/command/src/main/java/com/iluwatar/command/ShrinkSpell.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java
similarity index 65%
rename from command/src/main/java/com/iluwatar/command/ShrinkSpell.java
rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java
index 3f21fc7c1..44294b1db 100644
--- a/command/src/main/java/com/iluwatar/command/ShrinkSpell.java
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,39 +21,46 @@
* THE SOFTWARE.
*/
-package com.iluwatar.command;
+package com.iluwatar.filterer.threat;
+
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
/**
- * ShrinkSpell is a concrete command.
+ * Represents a simple threat.
*/
-public class ShrinkSpell implements Command {
+@ToString
+@EqualsAndHashCode
+@RequiredArgsConstructor
+public class SimpleThreat implements Threat {
- private Size oldSize;
- private Target target;
+ private final ThreatType threatType;
+ private final int id;
+ private final String name;
+ /**
+ * {@inheritDoc}
+ */
@Override
- public void execute(Target target) {
- oldSize = target.getSize();
- target.setSize(Size.SMALL);
- this.target = target;
+ public String name() {
+ return name;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
- public void undo() {
- if (oldSize != null && target != null) {
- var temp = target.getSize();
- target.setSize(oldSize);
- oldSize = temp;
- }
+ public int id() {
+ return id;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
- public void redo() {
- undo();
+ public ThreatType type() {
+ return threatType;
}
- @Override
- public String toString() {
- return "Shrink spell";
- }
}
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java
similarity index 50%
rename from semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java
rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java
index 5c2901efe..7a165c3f3 100644
--- a/semaphore/src/main/java/com/iluwatar/semaphore/FruitBowl.java
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,72 +21,60 @@
* THE SOFTWARE.
*/
-package com.iluwatar.semaphore;
+package com.iluwatar.filterer.threat;
+import com.iluwatar.filterer.domain.Filterer;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
/**
- * A FruitBowl contains Fruit.
+ * {@inheritDoc}
*/
-public class FruitBowl {
+@ToString
+@EqualsAndHashCode
+@RequiredArgsConstructor
+public class SimpleThreatAwareSystem implements ThreatAwareSystem {
- private final List fruit = new ArrayList<>();
+ private final String systemId;
+ private final List issues;
/**
- * Returns the amount of fruits left in bowl.
- *
- * @return The amount of Fruit left in the bowl.
+ * {@inheritDoc}
*/
- public int countFruit() {
- return fruit.size();
+ @Override
+ public String systemId() {
+ return systemId;
}
/**
- * Put an item of Fruit into the bowl.
- *
- * @param f fruit
+ * {@inheritDoc}
*/
- public void put(Fruit f) {
- fruit.add(f);
+ @Override
+ public List extends Threat> threats() {
+ return new ArrayList<>(issues);
}
/**
- * Take an item of Fruit out of the bowl.
- *
- * @return The Fruit taken out of the bowl, or null if empty.
+ * {@inheritDoc}
*/
- public Fruit take() {
- if (fruit.isEmpty()) {
- return null;
- } else {
- return fruit.remove(0);
- }
+ @Override
+ public Filterer extends ThreatAwareSystem, ? extends Threat> filtered() {
+ return this::filteredGroup;
}
- /**
- * toString method.
- */
- public String toString() {
- var apples = 0;
- var oranges = 0;
- var lemons = 0;
-
- for (var f : fruit) {
- switch (f.getType()) {
- case APPLE:
- apples++;
- break;
- case ORANGE:
- oranges++;
- break;
- case LEMON:
- lemons++;
- break;
- default:
- }
- }
-
- return apples + " Apples, " + oranges + " Oranges, and " + lemons + " Lemons";
+ private ThreatAwareSystem filteredGroup(Predicate super Threat> predicate) {
+ return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate));
}
+
+ private List filteredItems(Predicate super Threat> predicate) {
+ return this.issues.stream()
+ .filter(predicate)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
}
diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java b/filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java
new file mode 100644
index 000000000..7eeaa6be2
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java
@@ -0,0 +1,49 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+/**
+ * Represents a threat that can be detected in given system.
+ */
+public interface Threat {
+ /**
+ * Returns name of the threat.
+ *
+ * @return value representing name of the threat.
+ */
+ String name();
+
+ /**
+ * Returns unique id of the threat.
+ *
+ * @return value representing threat id.
+ */
+ int id();
+
+ /**
+ * Returns threat type.
+ * @return {@link ThreatType}
+ */
+ ThreatType type();
+}
diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java
new file mode 100644
index 000000000..4e34c99dd
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java
@@ -0,0 +1,55 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+import com.iluwatar.filterer.domain.Filterer;
+
+import java.util.List;
+
+/**
+ * Represents system that is aware of threats that are present in it.
+ */
+public interface ThreatAwareSystem {
+
+ /**
+ * Returns the system id.
+ *
+ * @return system id.
+ */
+ String systemId();
+
+ /**
+ * Returns list of threats for this system.
+ * @return list of threats for this system.
+ */
+ List extends Threat> threats();
+
+ /**
+ * Returns the instance of {@link Filterer} helper interface that allows to covariantly
+ * specify lower bound for predicate that we want to filter by.
+ * @return an instance of {@link Filterer} helper interface.
+ */
+ Filterer extends ThreatAwareSystem, ? extends Threat> filtered();
+
+}
diff --git a/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java
new file mode 100644
index 000000000..417db3e0c
--- /dev/null
+++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java
@@ -0,0 +1,30 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+public enum ThreatType {
+ TROJAN,
+ WORM,
+ ROOTKIT
+}
diff --git a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java b/filterer/src/test/java/com/iluwatar/filterer/AppTest.java
similarity index 88%
rename from mutex/src/test/java/com/iluwatar/mutex/AppTest.java
rename to filterer/src/test/java/com/iluwatar/filterer/AppTest.java
index 0bee249a6..9ba98dd23 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
+++ b/filterer/src/test/java/com/iluwatar/filterer/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,16 +21,13 @@
* THE SOFTWARE.
*/
-package com.iluwatar.mutex;
+package com.iluwatar.filterer;
import org.junit.jupiter.api.Test;
-/**
- * Application Test Entrypoint
- */
-public class AppTest {
+class AppTest {
@Test
- public void test() {
+ void shouldLaunchApp() {
App.main(new String[]{});
}
-}
+}
\ No newline at end of file
diff --git a/semaphore/src/test/java/com/iluwatar/semaphore/SemaphoreTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java
similarity index 58%
rename from semaphore/src/test/java/com/iluwatar/semaphore/SemaphoreTest.java
rename to filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java
index 6d64066fb..50fca774c 100644
--- a/semaphore/src/test/java/com/iluwatar/semaphore/SemaphoreTest.java
+++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,39 +21,31 @@
* THE SOFTWARE.
*/
-package com.iluwatar.semaphore;
+package com.iluwatar.filterer.threat;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
+import java.util.List;
import org.junit.jupiter.api.Test;
-/**
- * Test case for acquiring and releasing a Semaphore
- */
-public class SemaphoreTest {
+class SimpleProbabilisticThreatAwareSystemTest {
@Test
- public void acquireReleaseTest() {
- var sphore = new Semaphore(3);
+ void shouldFilterByProbability() {
+ //given
+ var trojan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99);
+ var rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8);
+ List probableThreats = List.of(trojan, rootkit);
- assertEquals(3, sphore.getAvailableLicenses());
+ var simpleProbabilisticThreatAwareSystem =
+ new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats);
- for (var i = 2; i >= 0; i--) {
- try {
- sphore.acquire();
- assertEquals(i, sphore.getAvailableLicenses());
- } catch (InterruptedException e) {
- fail(e.toString());
- }
- }
+ //when
+ var filtered = simpleProbabilisticThreatAwareSystem.filtered()
+ .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0);
- for (var i = 1; i <= 3; i++) {
- sphore.release();
- assertEquals(i, sphore.getAvailableLicenses());
- }
-
- sphore.release();
- assertEquals(3, sphore.getAvailableLicenses());
+ //then
+ assertEquals(filtered.threats().size(), 1);
+ assertEquals(filtered.threats().get(0), trojan);
}
-}
+}
\ No newline at end of file
diff --git a/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java
new file mode 100644
index 000000000..d8b28e18a
--- /dev/null
+++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java
@@ -0,0 +1,50 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.filterer.threat;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class SimpleThreatAwareSystemTest {
+ @Test
+ void shouldFilterByThreatType() {
+ //given
+ var rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit");
+ var trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan");
+ List threats = List.of(rootkit, trojan);
+
+ var threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats);
+
+ //when
+ var rootkitThreatAwareSystem = threatAwareSystem.filtered()
+ .by(threat -> threat.type() == ThreatType.ROOTKIT);
+
+ //then
+ assertEquals(rootkitThreatAwareSystem.threats().size(), 1);
+ assertEquals(rootkitThreatAwareSystem.threats().get(0), rootkit);
+ }
+}
\ No newline at end of file
diff --git a/fluentinterface/README.md b/fluentinterface/README.md
index 61c5f2eb5..8b3f80fae 100644
--- a/fluentinterface/README.md
+++ b/fluentinterface/README.md
@@ -9,23 +9,25 @@ 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.
## 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.
+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
+ * 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.
+> 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
@@ -33,7 +35,9 @@ In plain words
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).
+> 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**
@@ -134,29 +138,35 @@ result is printed afterwards.
.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
+```
+
+Program output:
+
+```java
+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.
## 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)
+* [Google Guava FluentIterable](https://github.com/google/guava/wiki/FunctionalExplained)
* [JOOQ](http://www.jooq.org/doc/3.0/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/)
* [Mockito](http://mockito.org/)
* [Java Hamcrest](http://code.google.com/p/hamcrest/wiki/Tutorial)
diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml
index 9eb063c13..8f5e8e175 100644
--- a/fluentinterface/pom.xml
+++ b/fluentinterface/pom.xml
@@ -2,7 +2,7 @@
+
+# Les patrons de conception implémentés en Java
+
+
+[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
+[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
+[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
+[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+[](#contributors-)
+
+
+# Introduction
+
+Le patron de conception est la meilleure formatalisation qu'un programmeur
+peut utiliser pour résoudre un problème lors d'une conception d'une application/system.
+
+Le patron de conception (design pattern) est là pour accélérer le processus de
+développement en fournissant des paradigmes éprouvés.
+
+La réutilisation de patron de conception aide à prévenir des problèmes subtiles mais
+qui sont à l'origine de problèmes majeures, comme cette pratique augmente la lisibilitée
+du code par les développeurs/architectes familiers avec l'utilisation de ces concepts.
+
+# Commencer
+
+Ce site présente des modèles de conception Java. Les solutions ont été développées par des
+développeurs et architectes expérimentés de la communauté open source. Les modèles peuvent être parcourus par leurs descriptions de haut niveau ou en regardant leur code source. Les exemples de code source sont bien commentés et peuvent être considérés comme tutoriels de programmation sur la façon d'implémenter un modèle spécifique. Nous utilisons le plus technologies Java open source éprouvées au combat.
+
+Avant de plonger dans le matériau, vous devez vous familiariser avec divers
+[Principes de conception de logiciels](https://java-design-patterns.com/principles/).
+
+Toutes les conceptions doivent être aussi simples que possible. Vous devriez commencer par KISS, YAGNI,
+et faire la chose la plus simple qui pourrait éventuellement fonctionner principes. Complexité et
+les modèles ne devraient être introduits que lorsqu'ils sont nécessaires pour
+extensibilité.
+
+Une fois que vous êtes familiarisé avec ces concepts, vous pouvez commencer à explorer
+[modèles de conception disponibles](https://java-design-patterns.com/patterns/) par tout
+des approches suivantes
+
+ - Recherchez un modèle spécifique par son nom. Vous n'en trouvez pas? Veuillez signaler un nouveau modèle [ici](https://github.com/iluwatar/java-design-patterns/issues).
+ - Utilisation de balises telles que `Performance`, `Gang of Four` ou `Data access`.
+ - Utilisation des catégories de modèles, `Créatif`, `Comportemental` et autres.
+
+J'espère que les solutions orientées objet présentées sur ce site vous seront utiles
+dans vos architectures et ayez autant de plaisir à les apprendre que nous en avons eu à les développer.
+
+# Comment contribuer
+
+Si vous souhaitez contribuer au projet, vous trouverez les informations pertinentes dans
+notre [wiki développeur](https://github.com/iluwatar/java-design-patterns/wiki). Nous aiderons
+vous et répondez à vos questions dans le [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns).
+
+# Licence
+
+Ce projet est concédé sous les termes de la licence MIT.
diff --git a/front-controller/pom.xml b/front-controller/pom.xml
index 34dabc182..55009eeb7 100644
--- a/front-controller/pom.xml
+++ b/front-controller/pom.xml
@@ -2,7 +2,7 @@
+
+# 자바로 구현된 디자인 패턴
+
+[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
+
+
+
+[](#contributors-)
+
+
+
+# 소개
+
+디자인 패턴은 프로그래머가 응용 프로그램이나 시스템을 디자인 할 때 일반적인 문제를 해결하는 데 사용할 수있는 가장 공식화 된 방법입니다.
+
+디자인 패턴은 테스트되고 입증 된 개발 패러다임을 제공하여 개발 프로세스 속도를 높일 수 있습니다.
+
+디자인 패턴을 재사용하면 주요 문제를 유발하는 미묘한 이슈들을 방지하는데 도움이 되며 또한 패턴에 익숙한 코더와 아키텍트의 코드 가독성도 향상됩니다.
+
+# 시작하기
+
+이 사이트는 Java 디자인 패턴을 보여줍니다. 이 솔루션은 오픈 소스 커뮤니티의 경험이 많은 프로그래머와 설계자가 개발했습니다. 패턴은 높은 수준의 설명이나 소스 코드를 통해 찾아 볼 수 있습니다. 소스 코드 예제는 잘 설명되어 있으며 특정 패턴을 구현하는 방법을 알려주는 프로그래밍 튜토리얼로 생각할 수 있습니다. 우리는 가장 널리 알려지고 실무에서 입증된 오픈 소스 Java 기술을 사용합니다.
+
+자료를 살펴보기 전에 다양한 [소프트웨어 설계 원칙](https://java-design-patterns.com/principles/)을 숙지해야합니다.
+
+모든 디자인은 가능한 한 단순해야합니다. 당신은 KISS, YAGNI로 시작해야하며, 원칙을 작동 할 수 있는 가장 단순한 일을 해야합니다. 복잡성과 패턴은 실용적인 확장성을 위해 필요할 때만 도입되어야합니다.
+
+이러한 개념에 익숙해지면 다음 접근 방식 중 하나를 이용하여 [사용 가능한 디자인 패턴](https://java-design-patterns.com/patterns/)으로 드릴다운 할 수 있습니다.
+
+- 이름으로 특정 패턴을 검색합니다. 찾을 수 없습니까? [여기](https://github.com/iluwatar/java-design-patterns/issues)에서 새 패턴을 보고하십시오.
+- `Performance`, `Gang of Four` 또는 `Data access` 태그 사용.
+- 패턴 카테고리, `Creational`, `Behavioral` 및 기타 사용
+
+이 사이트에 제시된 객체 지향 솔루션이 여러분의 아키텍처에서 유용하고 우리가 개발 한 것만큼 재미있게 배우기를 바랍니다.
+
+# 기여하는 방법
+
+프로젝트에 기여할 의향이 있다면 [developer wiki](https://github.com/iluwatar/java-design-patterns/wiki)에서 관련 정보를 찾을 수 있습니다. [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns)에서 귀하를 돕고 질문에 답변 해 드리겠습니다.
+
+# 특허
+
+이 프로젝트는 MIT 라이센스 조건에 따라 라이센스가 부여됩니다.
+
+# 기여자
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ko/adapter/README.md b/ko/adapter/README.md
new file mode 100644
index 000000000..8ef291972
--- /dev/null
+++ b/ko/adapter/README.md
@@ -0,0 +1,134 @@
+---
+layout: pattern
+title: Adapter
+folder: adapter
+permalink: "/patterns/adapter/"
+categories: Structural
+tags:
+- Gang of Four
+---
+
+## 또한 ~으로 알려진
+
+Wrapper
+
+## 의도
+
+클래스의 인터페이스를 클라이언트가 기대하는 다른 인터페이스로 변환합니다. adapter를 사용하면 호환되지 않는 인터페이스로 인해 같이 쓸 수 없는 클래스를 함께 작동 할 수 있습니다.
+
+## 설명
+
+예시
+
+> 메모리 카드에 몇 장의 사진이 있고 컴퓨터로 전송해야한다고 생각하십시오. 이들을 전송하려면 컴퓨터에 메모리 카드를 연결할 수 있도록 컴퓨터 포트와 호환되는 어댑터가 필요합니다. 이 경우 카드 리더는 어댑터입니다. 또 다른 예는 유명한 전원 어댑터입니다. 세 갈래 플러그는 두 갈래 콘센트에 연결할 수 없습니다. 두 갈래 콘센트와 호환되는 전원 어댑터를 사용해야합니다. 또 다른 예는 한 사람이 말한 단어를 다른 사람에게 번역하는 번역가입니다.
+
+평범하게 말하자면
+
+> adapter 패턴을 사용하면 호환되지 않는 개체를 adapter에 연결하여 다른 클래스와 호환되도록 할 수 있습니다.
+
+Wikipedia 말에 의하면
+
+> 소프트웨어 엔지니어링에서 adapter 패턴은 기존 클래스의 인터페이스를 다른 인터페이스로 사용할 수 있도록 하는 소프트웨어 디자인 패턴입니다. 소스 코드를 수정하지 않고 기존 클래스가 다른 클래스와 함께 작동하도록 만드는 데 자주 사용됩니다.
+
+**프로그램 코드 예제**
+
+조정 보트만 사용할 수 있고 전혀 항해할 수 없는 선장을 생각해보십시오.
+
+먼저 `RowingBoat` 및 `FishingBoat` 인터페이스가 있습니다.
+
+```java
+public interface RowingBoat {
+ void row();
+}
+
+public class FishingBoat {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);
+ public void sail() {
+ LOGGER.info("The fishing boat is sailing");
+ }
+}
+```
+
+그리고 선장은 `RowingBoat` 인터페이스를 이동할 수 있게 구현했습니다.
+
+```java
+public class Captain {
+
+ private final RowingBoat rowingBoat;
+ // default constructor and setter for rowingBoat
+ public Captain(RowingBoat rowingBoat) {
+ this.rowingBoat = rowingBoat;
+ }
+
+ public void row() {
+ rowingBoat.row();
+ }
+}
+```
+
+이제 해적이오고 있고 우리 선장이 탈출해야하는데 어선만 있습니다. 선장이 조정 보트 기술로 어선을 조작 할 수있는 adapter를 만들어야합니다.
+
+```java
+public class FishingBoatAdapter implements RowingBoat {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
+
+ private final FishingBoat boat;
+
+ public FishingBoatAdapter() {
+ boat = new FishingBoat();
+ }
+
+ @Override
+ public void row() {
+ boat.sail();
+ }
+}
+```
+
+이제 `Captain` 은 `FishingBoat` 를 사용하여 해적을 탈출 할 수 있습니다.
+
+```java
+var captain = new Captain(new FishingBoatAdapter());
+captain.row();
+```
+
+## 클레스 다이어그램
+
+
+
+## 적용 가능성
+
+다음과 같은 경우 adapter 패턴을 사용합니다.
+
+- 기존 클래스를 사용 하려는데 해당 인터페이스가 필요한 클래스와 일치하지 않습니다.
+- 관련이 없거나 예상치 못한 클래스, 즉 호환되는 인터페이스가 반드시 필요하지 않은 클래스와 협력하는 재사용 가능한 클래스를 만들고 싶습니다.
+- 기존의 여러 하위 클래스를 사용해야하지만 모든 하위 클래스를 하위 클래스로 지정하여 인터페이스를 조정하는 것은 비현실적입니다. 개체 adapter는 부모 클래스의 인터페이스를 조정할 수 있습니다.
+- 타사 라이브러리를 사용하는 대부분의 응용 프로그램은 adapter를 응용 프로그램과 타사 라이브러리 사이의 중간 계층으로 사용하여 라이브러리에서 응용 프로그램을 분리합니다. 다른 라이브러리를 사용해야하는 경우 애플리케이션 코드를 변경할 필요없이 새 라이브러리 용 adapter만 필요합니다.
+
+## 결과 :
+
+클래스 및 개체 adapter에는 서로 다른 장단점이 있습니다. 클래스 adapter
+
+- 구체적인 Adaptee 클래스를 커밋하여 Adaptee를 Target에 적용합니다. 결과적으로 클래스와 모든 하위 클래스를 조정하려는 경우 클래스 adapter가 작동하지 않습니다.
+- adapter는 Adaptee의 하위 클래스이기 때문에 Adaptee의 일부 동작을 오버라이드합니다.
+- 하나의 객체만 생성하고 adaptee를 얻기위해 위해 추가 포인터 간접 지정이 필요하지 않습니다.
+
+개체 adapter
+
+- 하나의 adapter가 많은 Adaptees, 즉 Adaptee 자체와 모든 하위 클래스 (있는 경우)와 함께 작동하도록합시다. adapter는 한 번에 모든 어댑터에 기능을 추가 할 수도 있습니다.
+- Adaptee 동작을 오버라이드하기가 더 어렵습니다. Adaptee를 서브 클래싱하고 어댑터가 Adaptee 자체가 아닌 서브 클래스를 참조하도록 해야합니다.
+
+## 실제 사례
+
+- [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
+- [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-)
+- [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-)
+- [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-)
+
+## 크레딧
+
+- [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)
+- [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
+- [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
+- [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
diff --git a/ko/factory/README.md b/ko/factory/README.md
new file mode 100644
index 000000000..d020a9edd
--- /dev/null
+++ b/ko/factory/README.md
@@ -0,0 +1,128 @@
+---
+layout: pattern
+title: Factory
+folder: factory
+permalink: "/patterns/factory/"
+categories: Creational
+tags:
+- Gang of Four
+---
+
+## 또한 ~으로 알려진
+
+- Simple Factory
+- Static Factory Method
+
+## 의도
+
+구현 논리를 숨기고 클라이언트 코드가 새 객체를 초기화하는 대신 사용에 집중하도록하기 위해 factory라는 클래스에 캡슐화 된 정적 메서드를 제공합니다.
+
+## 설명
+
+예시
+
+> SQLServer에 연결된 웹 응용 프로그램이 있지만 이제 Oracle로 전환하려고 합니다. 기존 소스 코드를 수정하지 않고 이를 수행하려면 주어진 데이터베이스에 대한 연결을 생성하기 위해 정적 메서드를 호출 할 수 있는 Simple Factory 패턴을 구현해야합니다.
+
+Wikipedia 말에 의하면
+
+> factory는 다른 객체를 생성하기위한 객체입니다. 공식적으로 factory는 다양한 프로토 타입 또는 클래스의 객체를 반환하는 함수 또는 메서드입니다.
+
+**프로그램 코드 예제**
+
+우리는 인터페이스 `Car` 와 두 가지 구현 `Ford` 와 `Ferrari`을 가지고 있습니다.
+
+```java
+public interface Car {
+ String getDescription();
+}
+
+public class Ford implements Car {
+
+ static final String DESCRIPTION = "This is Ford.";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
+
+public class Ferrari implements Car {
+
+ static final String DESCRIPTION = "This is Ferrari.";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
+```
+
+열거형은 우리가 지원하는 자동차 유형을 나타냅니다 ( `Ford` 및 `Ferrari` ).
+
+```java
+public enum CarType {
+
+ FORD(Ford::new),
+ FERRARI(Ferrari::new);
+
+ private final Supplier constructor;
+
+ CarType(Supplier constructor) {
+ this.constructor = constructor;
+ }
+
+ public Supplier getConstructor() {
+ return this.constructor;
+ }
+}
+```
+
+그런 다음 factory 클래스 `CarsFactory` 캡슐화 된 자동차 객체를 만드는 정적 메서드 `getCar` 가 있습니다.
+
+```java
+public class CarsFactory {
+
+ public static Car getCar(CarType type) {
+ return type.getConstructor().get();
+ }
+}
+```
+
+이제 클라이언트 코드에서 factory 클래스를 사용하여 다양한 유형의 자동차를 만들 수 있습니다.
+
+```java
+var car1 = CarsFactory.getCar(CarType.FORD);
+var car2 = CarsFactory.getCar(CarType.FERRARI);
+LOGGER.info(car1.getDescription());
+LOGGER.info(car2.getDescription());;
+```
+
+프로그램 출력 :
+
+```java
+This is Ford.
+This Ferrari.
+```
+
+## 클래스 다이어그램
+
+
+
+## 적용 가능성
+
+객체 생성 및 관리 방법이 아닌 객체 생성에만 관심이있을 때 Simple Factory 패턴을 사용합니다.
+
+장점
+
+- 모든 객체 생성을 한곳에 유지하고 코드베이스에 '새'키 값이 확산되는 것을 방지합니다.
+- 느슨하게 결합 된 코드를 작성할 수 있습니다. 주요 장점 중 일부는 더 나은 테스트 가능성, 이해하기 쉬운 코드, 교체 가능한 구성 요소, 확장성 및 격리된 기능을 포함합니다.
+
+단점
+
+- 코드는 생각보다 복잡해집니다.
+
+## 관련 패턴
+
+- [Factory Method](https://java-design-patterns.com/patterns/factory-method/)
+- [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
+- [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/)
diff --git a/ko/observer/README.md b/ko/observer/README.md
new file mode 100644
index 000000000..7f27e3fbf
--- /dev/null
+++ b/ko/observer/README.md
@@ -0,0 +1,165 @@
+---
+layout: pattern
+title: Observer
+folder: observer
+permalink: "/patterns/observer/"
+categories: Behavioral
+tags:
+- Gang Of Four
+- Reactive
+---
+
+## 또한 ~으로 알려진
+
+Dependents, Publish-Subscribe
+
+## 의도
+
+하나의 개체가 상태를 변경하면 모든 종속 항목에 알림이 전송되고 자동으로 업데이트 되도록 개체간의 일대 다 종속성을 정의합니다.
+
+## 설명
+
+예시
+
+> 멀리 떨어진 땅에는 호빗과 오크 종족이 살고 있습니다. 둘 다 대부분 야외에 있으므로 날씨 변화를 면밀히 따릅니다. 끊임없이 날씨를 관찰하고 있다고 말할 수 있습니다.
+
+평범하게 말하자면
+
+> observer로 등록하여 개체의 상태 변경을 수신합니다.
+
+Wikipedia 말에 의하면
+
+> observer 패턴은 주제라고하는 객체가 observer라고 하는 종속 항목 목록을 유지하고 일반적으로 메서드 중 하나를 호출하여 상태 변경을 자동으로 알리는 소프트웨어 디자인 패턴입니다.
+
+**프로그램 코드 예제**
+
+먼저 `WeatherObserver` 인터페이스와 우리의 종족 `Orcs` 와 `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 orcs 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");
+ }
+ }
+}
+```
+
+그리고 끊임없이 변화하는 `Weather` 가 있습니다.
+
+```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);
+ }
+ }
+}
+```
+
+여기에 전체 예제가 있습니다.
+
+```java
+ var weather = new Weather();
+ weather.addObserver(new Orcs());
+ weather.addObserver(new Hobbits());
+ weather.timePasses();
+ weather.timePasses();
+ weather.timePasses();
+ weather.timePasses();
+```
+
+프로그램 출력 :
+
+```
+The weather changed to rainy.
+The orcs are facing rainy weather now
+The hobbits are facing rainy weather now
+The weather changed to windy.
+The orcs are facing windy weather now
+The hobbits are facing windy weather now
+The weather changed to cold.
+The orcs are facing cold weather now
+The hobbits are facing cold weather now
+The weather changed to sunny.
+The orcs are facing sunny weather now
+The hobbits are facing sunny weather now
+```
+
+## 클래스 다이어그램
+
+
+
+## 적용 가능성
+
+다음 상황에서 관찰자 패턴을 사용하십시오.
+
+- 추상화에 두 가지 측면이 있을 때 하나는 다른 하나에 종속됩니다. 이러한 측면을 별도의 개체에 캡슐화하면 독립적으로 변경하고 재사용 할 수 있습니다.
+- 한 개체를 변경하려면 얼마나 다른 개체를 변경해야 하는지 알 수 없는 경우입니다.
+- 개체가 다른 개체가 누구인지 가정하지 않고 알릴 수 있어야하는 경우. 즉, 개체가 단단히 결합되는 것을 원하지 않습니다.
+
+## 일반적인 사용 사례
+
+- 한 개체를 변경하면 다른 개체도 변경됩니다.
+
+## 실제 사례
+
+- [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html)
+- [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html)
+- [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html)
+- [RxJava](https://github.com/ReactiveX/RxJava)
+
+## 크레딧
+
+- [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)
+- [Java Generics and Collections](https://www.amazon.com/gp/product/0596527756/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596527756&linkCode=as2&tag=javadesignpat-20&linkId=246e5e2c26fe1c3ada6a70b15afcb195)
+- [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
+- [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
diff --git a/ko/prototype/README.md b/ko/prototype/README.md
new file mode 100644
index 000000000..d15e6daaf
--- /dev/null
+++ b/ko/prototype/README.md
@@ -0,0 +1,87 @@
+---
+layout: pattern
+title: Prototype
+folder: prototype
+permalink: "/patterns/prototype/"
+categories: Creational
+tags:
+- Gang Of Four
+- Instantiation
+---
+
+## 의도
+
+prototype 인스턴스를 사용하여 만들 개체의 종류를 지정하고 prototype을 복사하여 새 개체를 만듭니다.
+
+## 설명
+
+먼저 성능 이점을 얻기 위해 prototype 패턴이 사용되지 않는다는 점에 유의해야합니다. 오직 prototype 인스턴스에서 새 개체를 만드는 데만 사용됩니다.
+
+예시
+
+> 복제된 양인 돌리에 대해 기억나십니까? 자세한 내용은 다루지 않겠습니다만 여기서 핵심은 복제에 관한 것입니다.
+
+평범한 말하자면
+
+> 복제를 통해 기존 개체를 기반으로 개체를 만듭니다.
+
+Wikipedia 말에 의하면
+
+> prototype 패턴은 소프트웨어 개발에서 생성 디자인 패턴입니다. 생성 할 개체의 유형이 새 개체를 생성하기 위해 복제되는 prototype 인스턴스에 의해 결정될 때 사용됩니다.
+
+간단히 말해, 객체를 처음부터 만들고 설정하는 문제를 겪는 대신 기존 객체의 복사본을 만들어 필요에 맞게 수정할 수 있습니다.
+
+**프로그램 코드 예제**
+
+Java에서는 `Cloneable` 을 구현하고 `Object` 에서 `clone` 을 오버라이딩하여 쉽게 수행 할 수 있습니다.
+
+```java
+class Sheep implements Cloneable {
+ private String name;
+ public Sheep(String name) { this.name = name; }
+ public void setName(String name) { this.name = name; }
+ public String getName() { return name; }
+ @Override
+ public Sheep clone() {
+ try {
+ return (Sheep)super.clone();
+ } catch(CloneNotSuportedException) {
+ throw new InternalError();
+ }
+ }
+}
+```
+
+그런 다음 아래와 같이 복제할 수 있습니다.
+
+```java
+var original = new Sheep("Jolly");
+System.out.println(original.getName()); // Jolly
+
+// Clone and modify what is required
+var cloned = original.clone();
+cloned.setName("Dolly");
+System.out.println(cloned.getName()); // Dolly
+```
+
+## 클래스 다이어그램
+
+
+
+## 적용 가능성
+
+시스템이 제품의 생성, 구성, 표현 및 표현 방식에 독립적이어야 할 때 prototype 패턴을 사용
+
+- 인스턴스화할 클래스가 런타임에 지정되는 경우 (예 : 동적 로딩)
+- 제품의 클래스 계층 구조와 유사한 팩토리의 클래스 계층 구조 구축을 방지해야할 경우
+- 클래스의 인스턴스가 몇 가지 다른 상태 조합 중 하나만 가질 수 있는 경우. 적절한 상태로 매번 클래스를 수동으로 인스턴스화하는 것보다 해당하는 수의 prototype을 설치하고 복제하는 것이 더 편리 할 수 있습니다.
+- 복제에 비해 개체 생성 비용이 많이 드는 경우.
+
+## 실제 사례
+
+- [java.lang.Object#clone()](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone%28%29)
+
+## 크레딧
+
+- [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)
+- [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
diff --git a/ko/singleton/README.md b/ko/singleton/README.md
new file mode 100644
index 000000000..8875e56eb
--- /dev/null
+++ b/ko/singleton/README.md
@@ -0,0 +1,84 @@
+---
+layout: pattern
+title: Singleton
+folder: singleton
+permalink: "/patterns/singleton/"
+categories: Creational
+tags:
+- Gang of Four
+---
+
+## 의도
+
+클래스에 인스턴스가 하나만 있는지 확인하고 이에 대한 전역 access point을 제공합니다.
+
+## 설명
+
+예시
+
+> 마법사들이 마법을 연구하는 상아탑은 단 하나뿐입니다. 마법사는 항상 동일한 마법의 상아탑을 사용합니다. 여기서 상아탑은 singleton입니다.
+
+평범하게 말하자면
+
+> 특정 클래스의 개체가 하나만 생성되도록합니다.
+
+Wikipedia 말에 의하면
+
+> 소프트웨어 엔지니어링에서 singleton 패턴은 클래스의 인스턴스화를 하나의 객체로 제한하는 소프트웨어 디자인 패턴입니다. 이는 시스템 전체에서 작업을 조정하는 데 정확히 하나의 개체가 필요할 때 유용합니다.
+
+**프로그램 코드 예제**
+
+Joshua Bloch, Effective Java 2nd Edition p.18
+
+> 단일 요소 열거형은 singleton을 구현하는 가장 좋은 방법입니다.
+
+```java
+public enum EnumIvoryTower {
+ INSTANCE
+}
+```
+
+그런 다음 사용하려면 :
+
+```java
+var enumIvoryTower1 = EnumIvoryTower.INSTANCE;
+var enumIvoryTower2 = EnumIvoryTower.INSTANCE;
+assertEquals(enumIvoryTower1, enumIvoryTower2); // true
+```
+
+## 클래스 다이어그램
+
+
+
+## 적용 가능성
+
+다음과 같은 경우 Singleton 패턴을 사용합니다.
+
+- 정확히 하나의 클래스 인스턴스가 있어야하며 잘 알려진 access point에서 클라이언트에 접근할 수 있어야합니다.
+- 단일 인스턴스가 서브 클래싱으로 확장 가능해야하고 클라이언트가 코드를 수정하지 않고 확장 인스턴스를 사용할 수 있어야 하는 경우
+
+## 일반적인 사용 사례
+
+- 로깅 클래스
+- 데이터베이스에 대한 연결 관리
+- 파일 관리자
+
+## 실제 사례
+
+- [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
+- [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--)
+- [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)
+
+## 결과
+
+- 자체 생성 및 수명주기를 제어하여 SRP (Single Responsibility Principle)를 위반합니다.
+- 이 개체가 사용하는 개체와 리소스가 할당 해제되는 것을 방지하는 전역 공유 인스턴스를 사용하도록 권장합니다.
+- 밀접하게 연결된 코드를 만듭니다. Singleton의 클라이언트는 테스트하기가 어려워집니다.
+- Singleton의 하위 클래스를 만드는 것이 거의 불가능합니다.
+
+## 크레딧
+
+- [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)
+- [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb)
+- [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
+- [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
diff --git a/layers/README.md b/layers/README.md
index 1e309f92b..1c8a695a0 100644
--- a/layers/README.md
+++ b/layers/README.md
@@ -10,26 +10,33 @@ tags:
---
## Intent
-Layers is an architectural pattern where software responsibilities are
- divided among the different layers of the application.
+
+Layers is an architectural pattern where software responsibilities are divided among the different
+layers of the application.
## Explanation
Real world example
-> Consider a web site displaying decorated cakes for weddings and such. Instead of the web page directly reaching into the database, it relies on a service to deliver this information. The service then queries the data layer to assimilate the needed information.
+> Consider a web site displaying decorated cakes for weddings and such. Instead of the web page
+> directly reaching into the database, it relies on a service to deliver this information. The
+> service then queries the data layer to assimilate the needed information.
-In Plain Words
+In plain words
-> With Layers architectural pattern different concerns reside on separate layers. View layer is interested only in rendering, service layer assembles the requested data from various sources, and data layer gets the bits from the data storage.
+> With Layers architectural pattern different concerns reside on separate layers. View layer is
+> interested only in rendering, service layer assembles the requested data from various sources, and
+> data layer gets the bits from the data storage.
Wikipedia says
-> In software engineering, multitier architecture (often referred to as n-tier architecture) or multilayered architecture is a client–server architecture in which presentation, application processing, and data management functions are physically separated.
+> In software engineering, multitier architecture (often referred to as n-tier architecture) or
+> multilayered architecture is a client–server architecture in which presentation, application
+> processing, and data management functions are physically separated.
**Programmatic Example**
-On the data layer, we keep our cake building blocks. Cakes consist of layers and topping.
+On the data layer, we keep our cake building blocks. `Cake` consist of layers and topping.
```java
@Entity
@@ -47,7 +54,7 @@ public class Cake {
}
```
-The service layer offers CakeBakingService for easy access to different aspects of cakes.
+The service layer offers `CakeBakingService` for easy access to different aspects of cakes.
```java
public interface CakeBakingService {
@@ -66,7 +73,7 @@ public interface CakeBakingService {
}
```
-On the top we have our view responsible of rendering the cakes.
+On the top we have our `View` responsible of rendering the cakes.
```java
public interface View {
@@ -75,10 +82,9 @@ public interface View {
}
+@Slf4j
public class CakeViewImpl implements View {
- private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class);
-
private final CakeBakingService cakeBakingService;
public CakeViewImpl(CakeBakingService cakeBakingService) {
@@ -92,14 +98,16 @@ public class CakeViewImpl implements View {
```
## Class diagram
+

## Applicability
+
Use the Layers architecture when
-* you want clearly divide software responsibilities into different parts of the program
-* you want to prevent a change from propagating throughout the application
-* you want to make your application more maintainable and testable
+* You want clearly divide software responsibilities into different parts of the program.
+* You want to prevent a change from propagating throughout the application.
+* You want to make your application more maintainable and testable.
## Credits
diff --git a/layers/pom.xml b/layers/pom.xml
index 2ebace18b..05392f78e 100644
--- a/layers/pom.xml
+++ b/layers/pom.xml
@@ -2,7 +2,7 @@
"-bookService" BookService
+BookServiceImpl --> "-designPatternBooks" Book
+BookViewModel --> "-bookList" Book
+BookViewModel --> "-selectedBook" Book
+BookServiceImpl ..|> BookService
+@enduml
\ No newline at end of file
diff --git a/model-view-viewmodel/lombok.config b/model-view-viewmodel/lombok.config
new file mode 100644
index 000000000..a23edb413
--- /dev/null
+++ b/model-view-viewmodel/lombok.config
@@ -0,0 +1,2 @@
+config.stopBubbling = true
+lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file
diff --git a/model-view-viewmodel/pom.xml b/model-view-viewmodel/pom.xml
new file mode 100644
index 000000000..971ae59f7
--- /dev/null
+++ b/model-view-viewmodel/pom.xml
@@ -0,0 +1,115 @@
+
+
+ 4.0.0
+
+ java-design-patterns
+ com.iluwatar
+ 1.24.0-SNAPSHOT
+
+ com.iluwatar
+ model-view-viewmodel
+ 1.24.0-SNAPSHOT
+
+ 9.0.0
+ 19.0
+ 9.4.28.v20200408
+ 2.1.1
+ 2.2
+ yyyy-MM-dd
+ -${project.version}-FL-${maven.build.timestamp}
+
+ war
+ model-view-viewmodel
+ model-view-viewmodel
+
+
+ GNU LESSER GENERAL PUBLIC LICENSE, Version 3
+ https://www.gnu.org/licenses/lgpl.html
+ repo
+
+
+
+
+ ZK CE
+ ZK CE Repository
+ https://mavensync.zkoss.org/maven2
+
+
+ ZK EVAL
+ ZK Evaluation Repository
+ https://mavensync.zkoss.org/eval
+
+
+
+
+ zkmaven
+ ZK Maven Plugin Repository
+ https://mavensync.zkoss.org/maven2/
+
+
+
+
+ org.zkoss.zk
+ zkbind
+ ${zk.version}
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ com.google.guava
+ guava-testlib
+ ${guava.version}
+ test
+
+
+
+ ${project.artifactId}
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ ${jetty-maven-plugin.version}
+
+
+ /${project.artifactId}
+ true
+
+ 5
+
+
+
+
+ maven-war-plugin
+ org.apache.maven.plugins
+ ${maven-war-plugin.version}
+
+
+
+ maven-assembly-plugin
+ ${maven-assembly-plugin.version}
+
+
+ webapp
+ package
+
+ single
+
+
+ model-view-viewmodel${packname}
+ false
+
+ src/main/assembly/webapp.xml
+
+
+
+
+
+
+
+
diff --git a/model-view-viewmodel/src/main/assembly/webapp.xml b/model-view-viewmodel/src/main/assembly/webapp.xml
new file mode 100644
index 000000000..153904efc
--- /dev/null
+++ b/model-view-viewmodel/src/main/assembly/webapp.xml
@@ -0,0 +1,25 @@
+
+ webapp
+
+ zip
+
+
+
+ ${project.basedir}/src/main/java
+ /${project.artifactId}/src
+
+
+ ${project.basedir}/src/main/webapp
+ /${project.artifactId}/WebContent
+
+
+
+
+ ${project.build.directory}/${project.artifactId}.war
+ /
+
+
+
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Lock.java b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/Book.java
similarity index 80%
rename from mutex/src/main/java/com/iluwatar/mutex/Lock.java
rename to model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/Book.java
index bd28c3c08..b2a924152 100644
--- a/mutex/src/main/java/com/iluwatar/mutex/Lock.java
+++ b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/Book.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,15 +21,17 @@
* THE SOFTWARE.
*/
-package com.iluwatar.mutex;
+package com.iluwatar.model.view.viewmodel;
-/**
- * Lock is an interface for a lock which can be acquired and released.
- */
-public interface Lock {
+import lombok.AllArgsConstructor;
+import lombok.Data;
- void acquire() throws InterruptedException;
+@AllArgsConstructor
+@Data
+public class Book {
- void release();
+ private String name;
+ private String author;
+ private String description;
}
diff --git a/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookService.java b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookService.java
new file mode 100644
index 000000000..f01066960
--- /dev/null
+++ b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookService.java
@@ -0,0 +1,10 @@
+package com.iluwatar.model.view.viewmodel;
+
+import java.util.List;
+
+public interface BookService {
+ /* List all books
+ * @return all books
+ */
+ public List load();
+}
diff --git a/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookServiceImpl.java b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookServiceImpl.java
new file mode 100644
index 000000000..e9b440843
--- /dev/null
+++ b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookServiceImpl.java
@@ -0,0 +1,38 @@
+package com.iluwatar.model.view.viewmodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BookServiceImpl implements BookService {
+ private List designPatternBooks = new ArrayList<>();
+
+ /** Initializes Book Data.
+ * To be used and passed along in load method
+ * In this case, list design pattern books are initialized to be loaded.
+ */
+ public BookServiceImpl() {
+ designPatternBooks.add(new Book(
+ "Head First Design Patterns: A Brain-Friendly Guide",
+ "Eric Freeman, Bert Bates, Kathy Sierra, Elisabeth Robson",
+ "Head First Design Patterns Description"));
+ designPatternBooks.add(new Book(
+ "Design Patterns: Elements of Reusable Object-Oriented Software",
+ "Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides",
+ "Design Patterns Description"));
+ designPatternBooks.add(new Book(
+ "Patterns of Enterprise Application Architecture", "Martin Fowler",
+ "Patterns of Enterprise Application Architecture Description"));
+ designPatternBooks.add(new Book(
+ "Design Patterns Explained", "Alan Shalloway, James Trott",
+ "Design Patterns Explained Description"));
+ designPatternBooks.add(new Book(
+ "Applying UML and Patterns: An Introduction to "
+ + "Object-Oriented Analysis and Design and Iterative Development",
+ "Craig Larman", "Applying UML and Patterns Description"));
+ }
+
+ public List load() {
+ return designPatternBooks;
+ }
+
+}
diff --git a/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookViewModel.java b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookViewModel.java
new file mode 100644
index 000000000..6563df723
--- /dev/null
+++ b/model-view-viewmodel/src/main/java/com/iluwatar/model/view/viewmodel/BookViewModel.java
@@ -0,0 +1,43 @@
+package com.iluwatar.model.view.viewmodel;
+
+import java.util.List;
+
+import org.zkoss.bind.annotation.Command;
+import org.zkoss.bind.annotation.NotifyChange;
+import org.zkoss.zk.ui.select.annotation.WireVariable;
+
+public class BookViewModel {
+
+ @WireVariable
+ private List bookList;
+ private Book selectedBook;
+ private BookService bookService = new BookServiceImpl();
+
+ public Book getSelectedBook() {
+ return selectedBook;
+ }
+
+ @NotifyChange("selectedBook")
+ public void setSelectedBook(Book selectedBook) {
+ this.selectedBook = selectedBook;
+ }
+
+ public List getBookList() {
+ return bookService.load();
+ }
+
+ /** Deleting a book.
+ * When event is triggered on click of Delete button,
+ * this method will be notified with the selected entry that will be referenced
+ * and used to delete the selected book from the list of books.
+ */
+ @Command
+ @NotifyChange({"selectedBook","bookList"})
+ public void deleteBook() {
+ if (selectedBook != null) {
+ getBookList().remove(selectedBook);
+ selectedBook = null;
+ }
+ }
+
+}
diff --git a/model-view-viewmodel/src/main/webapp/META-INF/MANIFEST.MF b/model-view-viewmodel/src/main/webapp/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..4e0a32ad6
--- /dev/null
+++ b/model-view-viewmodel/src/main/webapp/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Specification-Title: ZK Application
+Specification-Version: 1.0
+Specification-Vendor:
+Implementation-Title:
+Implementation-URL: http://your-website/
+Implementation-Version: 1.0
+Implementation-Vendor:
diff --git a/model-view-viewmodel/src/main/webapp/WEB-INF/web.xml b/model-view-viewmodel/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 000000000..24af77bbb
--- /dev/null
+++ b/model-view-viewmodel/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+ model-view-viewmodel
+
+
+
+ ZK listener for session cleanup
+ org.zkoss.zk.ui.http.HttpSessionListener
+
+
+ ZK loader for ZUML pages
+ zkLoader
+ org.zkoss.zk.ui.http.DHtmlLayoutServlet
+
+
+
+ update-uri
+ /zkau
+
+ 1
+
+
+ zkLoader
+ *.zul
+
+
+ zkLoader
+ *.zhtml
+
+
+ The asynchronous update engine for ZK
+ auEngine
+ org.zkoss.zk.au.http.DHtmlUpdateServlet
+
+
+ auEngine
+ /zkau/*
+
+
+ 60
+
+
+
+
+ doc
+ application/vnd.ms-word
+
+
+ gif
+ image/gif
+
+
+ htm
+ text/html
+
+
+ html
+ text/html
+
+
+ jpeg
+ image/jpeg
+
+
+ jpg
+ image/jpeg
+
+
+ js
+ text/javascript
+
+
+ pdf
+ application/pdf
+
+
+ png
+ image/png
+
+
+ txt
+ text/plain
+
+
+ xls
+ application/vnd.ms-excel
+
+
+ xml
+ text/xml
+
+
+ zhtml
+ text/html
+
+
+ zul
+ text/html
+
+
+
+ index.zul
+ index.zhtml
+ index.html
+ index.htm
+
+
diff --git a/model-view-viewmodel/src/main/webapp/index.zul b/model-view-viewmodel/src/main/webapp/index.zul
new file mode 100644
index 000000000..9cdab7144
--- /dev/null
+++ b/model-view-viewmodel/src/main/webapp/index.zul
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Book Name :
+
+
+ Book Author :
+
+
+ Book Description :
+
+
+
+
+
\ No newline at end of file
diff --git a/model-view-viewmodel/src/test/java/com/iluwatar/model/view/viewmodel/BookTest.java b/model-view-viewmodel/src/test/java/com/iluwatar/model/view/viewmodel/BookTest.java
new file mode 100644
index 000000000..40a4d89d0
--- /dev/null
+++ b/model-view-viewmodel/src/test/java/com/iluwatar/model/view/viewmodel/BookTest.java
@@ -0,0 +1,108 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.model.view.viewmodel;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import com.google.common.testing.EqualsTester;
+
+class BookTest {
+
+ BookViewModel bvm;
+ Book testBook;
+ List testBookList;
+ Book testBookTwo;
+ Book testBookThree;
+
+ @BeforeEach
+ void setUp() {
+ bvm = new BookViewModel();
+ testBook = new Book("Head First Design Patterns: A Brain-Friendly Guide",
+ "Eric Freeman, Bert Bates, Kathy Sierra, Elisabeth Robson",
+ "Head First Design Patterns Description");
+ testBookList = bvm.getBookList();
+ testBookTwo = new Book("Head First Design Patterns: A Brain-Friendly Guide",
+ "Eric Freeman, Bert Bates, Kathy Sierra, Elisabeth Robson",
+ "Head First Design Patterns Description");
+ testBookThree = new Book("Design Patterns: Elements of Reusable Object-Oriented Software",
+ "Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides",
+ "Design Patterns Description");
+ }
+
+ @Test
+ void testBookModel() {
+ assertNotNull(testBook);
+ }
+
+ @Test
+ void testEquals() {
+ new EqualsTester().addEqualityGroup(testBook, testBookTwo).testEquals();
+ }
+
+ @Test
+ void testToString() {
+ assertThat(testBook.toString(), is(testBookTwo.toString()));
+ assertThat(testBook.toString(), is(not(testBookThree.toString())));
+ }
+
+ @Test
+ void testHashCode() {
+ assertTrue(testBook.equals(testBookTwo) && testBookTwo.equals(testBook));
+ assertEquals(testBook.hashCode(), testBookTwo.hashCode());
+ }
+
+ @Test
+ void testLoadData() {
+ assertNotNull(testBookList);
+ assertTrue(testBookList.get(0).toString().contains("Head First Design Patterns"));
+ }
+
+ @Test
+ void testSelectedData() {
+ bvm.setSelectedBook(testBook);
+ assertNotNull(bvm.getSelectedBook());
+ assertEquals(testBook.toString(), bvm.getSelectedBook().toString());
+ assertTrue(true, bvm.getSelectedBook().toString());
+ }
+
+ @Test
+ void testDeleteData() {
+ bvm.setSelectedBook(testBook);
+ assertNotNull(bvm.getSelectedBook());
+ assertTrue(testBookList.get(0).toString().contains("Head First Design Patterns"));
+ bvm.deleteBook();
+ assertNull(bvm.getSelectedBook());
+ assertFalse(testBookList.get(0).toString().contains("Head First Design Patterns"));
+ }
+
+}
\ No newline at end of file
diff --git a/module/pom.xml b/module/pom.xml
index 5d9a6d529..ec71b8fad 100644
--- a/module/pom.xml
+++ b/module/pom.xml
@@ -2,7 +2,7 @@
"-lock" Lock
-Mutex ..|> Lock
-@enduml
\ No newline at end of file
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Jar.java b/mutex/src/main/java/com/iluwatar/mutex/Jar.java
deleted file mode 100644
index 4a0861e1a..000000000
--- a/mutex/src/main/java/com/iluwatar/mutex/Jar.java
+++ /dev/null
@@ -1,67 +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.
- */
-
-package com.iluwatar.mutex;
-
-/**
- * A Jar has a resource of beans which can only be accessed by a single Thief (thread) at any one
- * time. A Mutex lock is used to prevent more than one Thief taking a bean simultaneously.
- */
-public class Jar {
-
- /**
- * The lock which must be acquired to access the beans resource.
- */
- private final Lock lock;
-
- /**
- * The resource within the jar.
- */
- private int beans;
-
- public Jar(int beans, Lock lock) {
- this.beans = beans;
- this.lock = lock;
- }
-
- /**
- * Method for a thief to take a bean.
- */
- public boolean takeBean() {
- var success = false;
- try {
- lock.acquire();
- success = beans > 0;
- if (success) {
- beans = beans - 1;
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- lock.release();
- }
-
- return success;
- }
-
-}
diff --git a/mutex/src/main/java/com/iluwatar/mutex/Thief.java b/mutex/src/main/java/com/iluwatar/mutex/Thief.java
deleted file mode 100644
index a9a715970..000000000
--- a/mutex/src/main/java/com/iluwatar/mutex/Thief.java
+++ /dev/null
@@ -1,67 +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.
- */
-
-package com.iluwatar.mutex;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Thief is a class which continually tries to acquire a jar and take a bean from it. When the jar
- * is empty the thief stops.
- */
-public class Thief extends Thread {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(Thief.class);
-
- /**
- * The name of the thief.
- */
- private final String name;
-
- /**
- * The jar.
- */
- private final Jar jar;
-
- public Thief(String name, Jar jar) {
- this.name = name;
- this.jar = jar;
- }
-
- /**
- * In the run method the thief repeatedly tries to take a bean until none are left.
- */
- @Override
- public void run() {
- var beans = 0;
-
- while (jar.takeBean()) {
- beans = beans + 1;
- LOGGER.info("{} took a bean.", name);
- }
-
- LOGGER.info("{} took {} beans.", name, beans);
- }
-
-}
diff --git a/mvnw b/mvnw
new file mode 100755
index 000000000..41c0f0c23
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 000000000..ed1dd59b0
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,186 @@
+@REM
+@REM The MIT License
+@REM Copyright © 2014-2021 Ilkka Seppälä
+@REM
+@REM Permission is hereby granted, free of charge, to any person obtaining a copy
+@REM of this software and associated documentation files (the "Software"), to deal
+@REM in the Software without restriction, including without limitation the rights
+@REM to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+@REM copies of the Software, and to permit persons to whom the Software is
+@REM furnished to do so, subject to the following conditions:
+@REM
+@REM The above copyright notice and this permission notice shall be included in
+@REM all copies or substantial portions of the Software.
+@REM
+@REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+@REM IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+@REM FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+@REM AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+@REM LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+@REM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+@REM THE SOFTWARE.
+@REM
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml
index 0437c2da5..08966fdfa 100644
--- a/naked-objects/dom/pom.xml
+++ b/naked-objects/dom/pom.xml
@@ -2,7 +2,7 @@
"-sortOrder" SortOrder
+Builder ..+ ParameterObject
+ParameterObject --> "-DEFAULT_SORT_ORDER" SortOrder
+@enduml
diff --git a/mutex/pom.xml b/parameter-object/pom.xml
similarity index 91%
rename from mutex/pom.xml
rename to parameter-object/pom.xml
index 9cdff25e4..5fbf06066 100644
--- a/mutex/pom.xml
+++ b/parameter-object/pom.xml
@@ -2,7 +2,7 @@
+
4.0.0
+
com.iluwatar
java-design-patterns
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
pom
- 2014-2019
+
+ 2014-2021
+
UTF-8
+ 3.8.0.2131
5.2.18.Final
5.0.13.RELEASE
2.0.9.RELEASE
2.0.14.RELEASE
1.4.190
4.12
- 5.5.2
- ${junit.version}.2
- 1.0.2
+ 5.7.1
+ ${junit-jupiter.version}
3.8.1
- 0.8.4
+ 0.8.6
1.4
2.24.0
19.0
- 1.10.19
+ 3.5.6
2.22
4.0
3.12.1
@@ -52,8 +64,19 @@
2.3.1
2.3.2
1.3.2
- 1.19.0
+ 1.1.0
2.0.0
+ 3.5.0
+ 1.18.14
+ 1.10.21
+ 3.27.0-GA
+ 3.0.0-M5
+ 3.1.0
+ 0.3.1
+ 3.0
+ 1.4.8
+ 2.6
+
https://sonarcloud.io
iluwatar
@@ -61,6 +84,7 @@
${project.artifactId}
Java Design Patterns
+
abstract-factory
tls
@@ -88,6 +112,7 @@
state
strategy
template-method
+ version-number
visitor
double-checked-locking
servant
@@ -139,8 +164,6 @@
module
monad
mute-idiom
- mutex
- semaphore
hexagonal
abstract-document
aggregator-microservices
@@ -193,6 +216,14 @@
strangler
arrange-act-assert
transaction-script
+ registry
+ filterer
+ factory
+ separated-interface
+ special-case
+ parameter-object
+ active-object
+ model-view-viewmodel
@@ -204,6 +235,18 @@
+
+ net.bytebuddy
+ byte-buddy
+ ${byte-buddy.version}
+ test
+
+
+ net.bytebuddy
+ byte-buddy-agent
+ ${byte-buddy.version}
+ test
+
org.hibernate
hibernate-core
@@ -246,12 +289,6 @@
camel-stream
${camel.version}
-
- junit
- junit
- ${junit.version}
- test
-
org.junit.jupiter
junit-jupiter-api
@@ -282,12 +319,6 @@
${junit-vintage.version}
test
-
- com.github.sbrannen
- spring-test-junit5
- ${sping-test-junit5.version}
- test
-
org.mockito
mockito-core
@@ -332,17 +363,21 @@
org.javassist
javassist
- 3.26.0-GA
+ ${javassist.version}
com.github.stefanbirkner
- system-rules
- ${system-rules.version}
+ system-lambda
+ ${system-lambda.version}
test
-
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
-
org.slf4j
@@ -359,6 +394,12 @@
logback-core
${logback.version}
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
@@ -373,16 +414,19 @@
11
+
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M5
+ ${maven-surefire-plugin.version}
+
org.springframework.boot
spring-boot-maven-plugin
${spring-boot.version}
+
org.apache.maven.plugins
@@ -405,10 +449,11 @@
+
org.sonarsource.scanner.maven
sonar-maven-plugin
- 3.7.0.1746
+ ${sonar-maven-plugin.version}
@@ -417,7 +462,7 @@
org.apache.maven.plugins
maven-checkstyle-plugin
- 3.1.0
+ ${maven-checkstyle-plugin.version}
validate
@@ -443,7 +488,7 @@
org.commonjava.maven.plugins
directory-maven-plugin
- 0.3.1
+ ${directory-maven-plugin.version}
directories
@@ -461,10 +506,11 @@
+
com.mycila
license-maven-plugin
- 3.0
+ ${license-maven-plugin.version}
com/mycila/maven/plugin/license/templates/MIT.txt
@@ -515,7 +561,7 @@
com.iluwatar.urm
urm-maven-plugin
- 1.4.8
+ ${urm-maven-plugin.version}
${project.basedir}/etc
@@ -535,7 +581,6 @@
-
diff --git a/priority-queue/README.md b/priority-queue/README.md
index 924d7169f..f657b80c7 100644
--- a/priority-queue/README.md
+++ b/priority-queue/README.md
@@ -10,19 +10,202 @@ tags:
---
## Intent
-Prioritize requests sent to services so that requests with a higher priority are received and processed more quickly than those of a lower priority. This pattern is useful in applications that offer different service level guarantees to individual clients.
+
+Prioritize requests sent to services so that requests with a higher priority are received and
+processed more quickly than those of a lower priority. This pattern is useful in applications that
+offer different service level guarantees to individual clients.
## Explanation
-Applications may delegate specific tasks to other services; for example, to perform background processing or to integrate with other applications or services. In the cloud, a message queue is typically used to delegate tasks to background processing. In many cases the order in which requests are received by a service is not important. However, in some cases it may be necessary to prioritize specific requests. These requests should be processed earlier than others of a lower priority that may have been sent previously by the application.
+
+Applications may delegate specific tasks to other services; for example, to perform background
+processing or to integrate with other applications or services. In the cloud, a message queue is
+typically used to delegate tasks to background processing. In many cases the order in which requests
+are received by a service is not important. However, in some cases it may be necessary to prioritize
+specific requests. These requests should be processed earlier than others of a lower priority that
+may have been sent previously by the application.
+
+Real world example
+
+> Imagine a video processing service with free and premium customers. The requests coming from the
+> paying premium customers should be prioritized over the others.
+
+In plain words
+
+> Priority Queue enables processing of high priority messages first, regardless of queue size or
+> message age.
+
+Wikipedia says
+
+> In computer science, a priority queue is an abstract data type similar to regular queue or stack
+> data structure in which each element additionally has a "priority" associated with it. In a
+> priority queue, an element with high priority is served before an element with low priority.
+
+**Programmatic Example**
+
+Looking at the video processing example from above, let's first see the `Message` structure.
+
+```java
+public class Message implements Comparable {
+
+ private final String message;
+ private final int priority; // define message priority in queue
+
+ public Message(String message, int priority) {
+ this.message = message;
+ this.priority = priority;
+ }
+
+ @Override
+ public int compareTo(Message o) {
+ return priority - o.priority;
+ }
+ ...
+}
+```
+
+Here's `PriorityMessageQueue` that handles storing the messages and serving them in priority
+order.
+
+```java
+public class PriorityMessageQueue {
+
+ ...
+
+ public T remove() {
+ if (isEmpty()) {
+ return null;
+ }
+
+ final var root = queue[0];
+ queue[0] = queue[size - 1];
+ size--;
+ maxHeapifyDown();
+ return root;
+ }
+
+ public void add(T t) {
+ ensureCapacity();
+ queue[size] = t;
+ size++;
+ maxHeapifyUp();
+ }
+
+ ...
+}
+```
+
+`QueueManager` has a `PriorityMessageQueue` and makes it easy to `publishMessage` and
+`receiveMessage`.
+
+```java
+public class QueueManager {
+
+ private final PriorityMessageQueue messagePriorityMessageQueue;
+
+ public QueueManager(int initialCapacity) {
+ messagePriorityMessageQueue = new PriorityMessageQueue<>(new Message[initialCapacity]);
+ }
+
+ public void publishMessage(Message message) {
+ messagePriorityMessageQueue.add(message);
+ }
+
+ public Message receiveMessage() {
+ if (messagePriorityMessageQueue.isEmpty()) {
+ return null;
+ }
+ return messagePriorityMessageQueue.remove();
+ }
+}
+```
+
+`Worker` constantly polls `QueueManager` for highest priority message and processes it.
+
+```java
+@Slf4j
+public class Worker {
+
+ private final QueueManager queueManager;
+
+ public Worker(QueueManager queueManager) {
+ this.queueManager = queueManager;
+ }
+
+ public void run() throws Exception {
+ while (true) {
+ var message = queueManager.receiveMessage();
+ if (message == null) {
+ LOGGER.info("No Message ... waiting");
+ Thread.sleep(200);
+ } else {
+ processMessage(message);
+ }
+ }
+ }
+
+ private void processMessage(Message message) {
+ LOGGER.info(message.toString());
+ }
+}
+```
+
+Here's the full example how we create an instance of `QueueManager` and process messages using
+`Worker`.
+
+```java
+ var queueManager = new QueueManager(100);
+
+ for (var i = 0; i < 100; i++) {
+ queueManager.publishMessage(new Message("Low Message Priority", 0));
+ }
+
+ for (var i = 0; i < 100; i++) {
+ queueManager.publishMessage(new Message("High Message Priority", 1));
+ }
+
+ var worker = new Worker(queueManager);
+ worker.run();
+```
+
+Program output:
+
+```
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='High Message Priority', priority=1}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+Message{message='Low Message Priority', priority=0}
+No Message ... waiting
+No Message ... waiting
+No Message ... waiting
+```
+
## Class diagram
+

## Applicability
-Use the Priority Queue 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..
+* Different users or tenants should be served with different priority.
## Credits
diff --git a/priority-queue/pom.xml b/priority-queue/pom.xml
index 7f435f489..0969623d9 100644
--- a/priority-queue/pom.xml
+++ b/priority-queue/pom.xml
@@ -2,7 +2,7 @@
"-addCustomer" CustomerRegistry
+@enduml
diff --git a/registry/pom.xml b/registry/pom.xml
new file mode 100644
index 000000000..2b82d45bf
--- /dev/null
+++ b/registry/pom.xml
@@ -0,0 +1,66 @@
+
+
+
+ 4.0.0
+
+
+ com.iluwatar
+ java-design-patterns
+ 1.24.0-SNAPSHOT
+
+ registry
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.registry.App
+
+
+
+
+
+
+
+
+
+
diff --git a/registry/src/main/java/com/iluwatar/registry/App.java b/registry/src/main/java/com/iluwatar/registry/App.java
new file mode 100644
index 000000000..de6fa8464
--- /dev/null
+++ b/registry/src/main/java/com/iluwatar/registry/App.java
@@ -0,0 +1,50 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.registry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class App {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ CustomerRegistry customerRegistry = CustomerRegistry.getInstance();
+ var john = new Customer("1", "John");
+ customerRegistry.addCustomer(john);
+
+ var julia = new Customer("2", "Julia");
+ customerRegistry.addCustomer(julia);
+
+ LOGGER.info("John {}", customerRegistry.getCustomer("1"));
+ LOGGER.info("Julia {}", customerRegistry.getCustomer("2"));
+ }
+
+}
diff --git a/registry/src/main/java/com/iluwatar/registry/Customer.java b/registry/src/main/java/com/iluwatar/registry/Customer.java
new file mode 100644
index 000000000..97e77af98
--- /dev/null
+++ b/registry/src/main/java/com/iluwatar/registry/Customer.java
@@ -0,0 +1,51 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.registry;
+
+public class Customer {
+
+ private final String id;
+ private final String name;
+
+ public Customer(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return "Customer{"
+ + "id='" + id + '\''
+ + ", name='" + name + '\''
+ + '}';
+ }
+}
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java b/registry/src/main/java/com/iluwatar/registry/CustomerRegistry.java
similarity index 63%
rename from semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java
rename to registry/src/main/java/com/iluwatar/registry/CustomerRegistry.java
index 1f4026b92..b4279e1be 100644
--- a/semaphore/src/main/java/com/iluwatar/semaphore/Fruit.java
+++ b/registry/src/main/java/com/iluwatar/registry/CustomerRegistry.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,44 +21,31 @@
* THE SOFTWARE.
*/
-package com.iluwatar.semaphore;
+package com.iluwatar.registry;
-/**
- * Fruit is a resource stored in a FruitBowl.
- */
-public class Fruit {
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
- /**
- * Enumeration of Fruit Types.
- */
- public enum FruitType {
- ORANGE, APPLE, LEMON
+public final class CustomerRegistry {
+
+ private static final CustomerRegistry instance = new CustomerRegistry();
+
+ public static CustomerRegistry getInstance() {
+ return instance;
}
- private final FruitType type;
+ private final Map customerMap;
- public Fruit(FruitType type) {
- this.type = type;
+ private CustomerRegistry() {
+ customerMap = new ConcurrentHashMap<>();
}
- public FruitType getType() {
- return type;
+ public Customer addCustomer(Customer customer) {
+ return customerMap.put(customer.getId(), customer);
}
- /**
- * toString method.
- */
- public String toString() {
- switch (type) {
- case ORANGE:
- return "Orange";
- case APPLE:
- return "Apple";
- case LEMON:
- return "Lemon";
- default:
- return "";
- }
+ public Customer getCustomer(String id) {
+ return customerMap.get(id);
}
}
diff --git a/registry/src/test/java/com/iluwatar/registry/CustomerRegistryTest.java b/registry/src/test/java/com/iluwatar/registry/CustomerRegistryTest.java
new file mode 100644
index 000000000..c25e7f7c6
--- /dev/null
+++ b/registry/src/test/java/com/iluwatar/registry/CustomerRegistryTest.java
@@ -0,0 +1,66 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.registry;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class CustomerRegistryTest {
+
+ private static CustomerRegistry customerRegistry;
+
+ @BeforeAll
+ public static void setUp() {
+ customerRegistry = CustomerRegistry.getInstance();
+ }
+
+ @Test
+ public void shouldBeAbleToAddAndQueryCustomerObjectFromRegistry() {
+ Customer john = new Customer("1", "john");
+ Customer julia = new Customer("2", "julia");
+
+ customerRegistry.addCustomer(john);
+ customerRegistry.addCustomer(julia);
+
+ Customer customerWithId1 = customerRegistry.getCustomer("1");
+ assertNotNull(customerWithId1);
+ assertEquals("1", customerWithId1.getId());
+ assertEquals("john", customerWithId1.getName());
+
+ Customer customerWithId2 = customerRegistry.getCustomer("2");
+ assertNotNull(customerWithId2);
+ assertEquals("2", customerWithId2.getId());
+ assertEquals("julia", customerWithId2.getName());
+ }
+
+ @Test
+ void shouldReturnNullWhenQueriedCustomerIsNotInRegistry() {
+ Customer customerWithId5 = customerRegistry.getCustomer("5");
+ assertNull(customerWithId5);
+ }
+}
diff --git a/repository/README.md b/repository/README.md
index ad603ee2b..ab13934bd 100644
--- a/repository/README.md
+++ b/repository/README.md
@@ -9,26 +9,33 @@ 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.
+> 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.
+> 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.
+> 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.
+Let's first look at the person entity that we need to persist.
```java
@Entity
@@ -39,107 +46,23 @@ public class Person {
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);
- }
+ // getters and setters ->
+ ...
}
```
-We are using Spring Data to create the repository so it becomes really simple.
+We are using Spring Data to create the `PersonRepository` so it becomes really simple.
```java
@Repository
@@ -150,7 +73,7 @@ public interface PersonRepository
}
```
-Additionally we define a helper class for specification queries.
+Additionally we define a helper class `PersonSpecifications` for specification queries.
```java
public class PersonSpecifications {
@@ -189,7 +112,7 @@ public class PersonSpecifications {
}
```
-And here's the repository in action.
+And here's the repository example in action.
```java
var peter = new Person("Peter", "Sagan", 17);
@@ -226,30 +149,36 @@ And here's the repository in action.
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]
+```
+
+Program output:
+
+```
+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
+

## Applicability
+
Use the Repository pattern when
-* The number of domain objects is large
-* You want to avoid duplication of query code
-* You want to keep the database querying code in single place
-* You have multiple data sources
+* The number of domain objects is large.
+* You want to avoid duplication of query code.
+* You want to keep the database querying code in single place.
+* You have multiple data sources.
## Real world examples
diff --git a/repository/pom.xml b/repository/pom.xml
index 0b98cdb41..b92c606ba 100644
--- a/repository/pom.xml
+++ b/repository/pom.xml
@@ -2,7 +2,7 @@
"-type" FruitType
-FruitShop --> "-semaphore" Semaphore
-FruitBowl --> "-fruit" Fruit
-Semaphore ..|> Lock
-@enduml
\ No newline at end of file
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/App.java b/semaphore/src/main/java/com/iluwatar/semaphore/App.java
deleted file mode 100644
index ebb35037f..000000000
--- a/semaphore/src/main/java/com/iluwatar/semaphore/App.java
+++ /dev/null
@@ -1,50 +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.
- */
-
-package com.iluwatar.semaphore;
-
-/**
- * A Semaphore mediates access by a group of threads to a pool of resources.
- *
- * In this example a group of customers are taking fruit from a fruit shop. There is a bowl each
- * of apples, oranges and lemons. Only one customer can access a bowl simultaneously. A Semaphore is
- * used to indicate how many resources are currently available and must be acquired in order for a
- * bowl to be given to a customer. Customers continually try to take fruit until there is no fruit
- * left in the shop.
- */
-public class App {
-
- /**
- * main method.
- */
- public static void main(String[] args) {
- var shop = new FruitShop();
- new Customer("Peter", shop).start();
- new Customer("Paul", shop).start();
- new Customer("Mary", shop).start();
- new Customer("John", shop).start();
- new Customer("Ringo", shop).start();
- new Customer("George", shop).start();
- }
-
-}
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/Customer.java b/semaphore/src/main/java/com/iluwatar/semaphore/Customer.java
deleted file mode 100644
index 47f503a06..000000000
--- a/semaphore/src/main/java/com/iluwatar/semaphore/Customer.java
+++ /dev/null
@@ -1,82 +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.
- */
-
-package com.iluwatar.semaphore;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A Customer attempts to repeatedly take Fruit from the FruitShop by taking Fruit from FruitBowl
- * instances.
- */
-public class Customer extends Thread {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(Customer.class);
-
- /**
- * Name of the Customer.
- */
- private final String name;
-
- /**
- * The FruitShop he is using.
- */
- private final FruitShop fruitShop;
-
- /**
- * Their bowl of Fruit.
- */
- private final FruitBowl fruitBowl;
-
- /**
- * Customer constructor.
- */
- public Customer(String name, FruitShop fruitShop) {
- this.name = name;
- this.fruitShop = fruitShop;
- this.fruitBowl = new FruitBowl();
- }
-
- /**
- * The Customer repeatedly takes Fruit from the FruitShop until no Fruit remains.
- */
- public void run() {
-
- while (fruitShop.countFruit() > 0) {
- var bowl = fruitShop.takeBowl();
- if (bowl != null) {
- var fruit = bowl.take();
- if (fruit != null) {
- LOGGER.info("{} took an {}", name, fruit);
- fruitBowl.put(fruit);
- fruitShop.returnBowl(bowl);
- }
- }
- }
-
- LOGGER.info("{} took {}", name, fruitBowl);
-
- }
-
-}
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/FruitShop.java b/semaphore/src/main/java/com/iluwatar/semaphore/FruitShop.java
deleted file mode 100644
index c74145610..000000000
--- a/semaphore/src/main/java/com/iluwatar/semaphore/FruitShop.java
+++ /dev/null
@@ -1,120 +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.
- */
-
-package com.iluwatar.semaphore;
-
-/**
- * A FruitShop contains three FruitBowl instances and controls access to them.
- */
-public class FruitShop {
-
- /**
- * The FruitBowl instances stored in the class.
- */
- private final FruitBowl[] bowls = {
- new FruitBowl(),
- new FruitBowl(),
- new FruitBowl()
- };
-
- /**
- * Access flags for each of the FruitBowl instances.
- */
- private final boolean[] available = {
- true,
- true,
- true
- };
-
- /**
- * The Semaphore that controls access to the class resources.
- */
- private final Semaphore semaphore;
-
- /**
- * FruitShop constructor.
- */
- public FruitShop() {
- for (var i = 0; i < 100; i++) {
- bowls[0].put(new Fruit(Fruit.FruitType.APPLE));
- bowls[1].put(new Fruit(Fruit.FruitType.ORANGE));
- bowls[2].put(new Fruit(Fruit.FruitType.LEMON));
- }
-
- semaphore = new Semaphore(3);
- }
-
- /**
- * Returns the amount of fruits left in shop.
- *
- * @return The amount of Fruit left in the shop.
- */
- public synchronized int countFruit() {
- return bowls[0].countFruit() + bowls[1].countFruit() + bowls[2].countFruit();
- }
-
- /**
- * Method called by Customer to get a FruitBowl from the shop. This method will try to acquire the
- * Semaphore before returning the first available FruitBowl.
- */
- public synchronized FruitBowl takeBowl() {
-
- FruitBowl bowl = null;
-
- try {
- semaphore.acquire();
-
- if (available[0]) {
- bowl = bowls[0];
- available[0] = false;
- } else if (available[1]) {
- bowl = bowls[1];
- available[1] = false;
- } else if (available[2]) {
- bowl = bowls[2];
- available[2] = false;
- }
-
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- semaphore.release();
- }
- return bowl;
- }
-
- /**
- * Method called by a Customer instance to return a FruitBowl to the shop. This method releases
- * the Semaphore, making the FruitBowl available to another Customer.
- */
- public synchronized void returnBowl(FruitBowl bowl) {
- if (bowl == bowls[0]) {
- available[0] = true;
- } else if (bowl == bowls[1]) {
- available[1] = true;
- } else if (bowl == bowls[2]) {
- available[2] = true;
- }
- }
-
-}
diff --git a/semaphore/src/main/java/com/iluwatar/semaphore/Semaphore.java b/semaphore/src/main/java/com/iluwatar/semaphore/Semaphore.java
deleted file mode 100644
index 48b008fdd..000000000
--- a/semaphore/src/main/java/com/iluwatar/semaphore/Semaphore.java
+++ /dev/null
@@ -1,77 +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.
- */
-
-package com.iluwatar.semaphore;
-
-/**
- * Semaphore is an implementation of a semaphore lock.
- */
-public class Semaphore implements Lock {
-
- private final int licenses;
- /**
- * The number of concurrent resource accesses which are allowed.
- */
- private int counter;
-
- public Semaphore(int licenses) {
- this.licenses = licenses;
- this.counter = licenses;
- }
-
- /**
- * Returns the number of licenses managed by the Semaphore.
- */
- public int getNumLicenses() {
- return licenses;
- }
-
- /**
- * Returns the number of available licenses.
- */
- public int getAvailableLicenses() {
- return counter;
- }
-
- /**
- * Method called by a thread to acquire the lock. If there are no resources available this will
- * wait until the lock has been released to re-attempt the acquire.
- */
- public synchronized void acquire() throws InterruptedException {
- while (counter == 0) {
- wait();
- }
- counter = counter - 1;
- }
-
- /**
- * Method called by a thread to release the lock.
- */
- public synchronized void release() {
- if (counter < licenses) {
- counter = counter + 1;
- notify();
- }
- }
-
-}
diff --git a/separated-interface/README.md b/separated-interface/README.md
new file mode 100644
index 000000000..35c9e5fe0
--- /dev/null
+++ b/separated-interface/README.md
@@ -0,0 +1,138 @@
+---
+layout: pattern
+title: Separated Interface
+folder: separated-interface
+permalink: /patterns/separated-interface/
+categories: Structural
+tags:
+ - Decoupling
+---
+
+
+## Intent
+
+Separate the interface definition and implementation in different packages. This allows the client
+to be completely unaware of the implementation.
+
+## Explanation
+
+Real world example
+
+> An Invoice generator may be created with ability to use different Tax calculators that may be
+> added in the invoice depending upon type of purchase, region etc.
+
+In plain words
+
+> Separated interface pattern encourages to keep the implementations of an interface decoupled from
+> the client and its definition, so the client is not dependent on the implementation.
+
+A client code may abstract some specific functionality to an interface, and define the definition of
+the interface as an SPI ([Service Programming Interface](https://en.wikipedia.org/wiki/Service_provider_interface)
+is an API intended and open to be implemented or extended by a third party). Another package may
+implement this interface definition with a concrete logic, which will be injected into the client
+code at runtime (with a third class, injecting the implementation in the client) or at compile time
+(using Plugin pattern with some configurable file).
+
+**Programmatic Example**
+
+**Client**
+
+`InvoiceGenerator` class accepts the cost of the product and calculates the total
+amount payable inclusive of tax.
+
+```java
+public class InvoiceGenerator {
+
+ private final TaxCalculator taxCalculator;
+
+ private final double amount;
+
+ public InvoiceGenerator(double amount, TaxCalculator taxCalculator) {
+ this.amount = amount;
+ this.taxCalculator = taxCalculator;
+ }
+
+ public double getAmountWithTax() {
+ return amount + taxCalculator.calculate(amount);
+ }
+
+}
+```
+
+The tax calculation logic is delegated to the `TaxCalculator` interface.
+
+```java
+public interface TaxCalculator {
+
+ double calculate(double amount);
+
+}
+```
+
+**Implementation package**
+
+In another package (which the client is completely unaware of) there exist multiple implementations
+of the `TaxCalculator` interface. `ForeignTaxCalculator` is one of them which levies 60% tax
+for international products.
+
+```java
+public class ForeignTaxCalculator implements TaxCalculator {
+
+ public static final double TAX_PERCENTAGE = 60;
+
+ @Override
+ public double calculate(double amount) {
+ return amount * TAX_PERCENTAGE / 100.0;
+ }
+
+}
+```
+
+Another is `DomesticTaxCalculator` which levies 20% tax for international products.
+
+```java
+public class DomesticTaxCalculator implements TaxCalculator {
+
+ public static final double TAX_PERCENTAGE = 20;
+
+ @Override
+ public double calculate(double amount) {
+ return amount * TAX_PERCENTAGE / 100.0;
+ }
+
+}
+```
+
+These both implementations are instantiated and injected in the client class by the ```App.java```
+class.
+
+```java
+ var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST, new ForeignTaxCalculator());
+
+ LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax());
+
+ var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTaxCalculator());
+
+ LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax());
+```
+
+## Class diagram
+
+
+
+## Applicability
+
+Use the Separated interface pattern when
+
+* You are developing a framework package, and your framework needs to call some application code through interfaces.
+* You have separate packages implementing the functionalities which may be plugged in your client code at runtime or compile-time.
+* Your code resides in a layer that is not allowed to call the interface implementation layer by rule. For example, a domain layer needs to call a data mapper.
+
+## Tutorial
+
+* [Separated Interface Tutorial](https://www.youtube.com/watch?v=d3k-hOA7k2Y)
+
+## Credits
+
+* [Martin Fowler](https://www.martinfowler.com/eaaCatalog/separatedInterface.html)
+* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=e08dfb7f2cf6153542ef1b5a00b10abc)
diff --git a/separated-interface/etc/class_diagram.png b/separated-interface/etc/class_diagram.png
new file mode 100644
index 000000000..10d509801
Binary files /dev/null and b/separated-interface/etc/class_diagram.png differ
diff --git a/separated-interface/etc/separated-interface.urm.puml b/separated-interface/etc/separated-interface.urm.puml
new file mode 100644
index 000000000..eab2ad60c
--- /dev/null
+++ b/separated-interface/etc/separated-interface.urm.puml
@@ -0,0 +1,36 @@
+@startuml
+package com.iluwatar.separatedinterface {
+ class App {
+ - LOGGER : Logger {static}
+ + PRODUCT_COST : double {static}
+ + App()
+ + main(args : String[]) {static}
+ }
+}
+package com.iluwatar.separatedinterface.taxes {
+ class DomesticTaxCalculator {
+ + TAX_PERCENTAGE : double {static}
+ + DomesticTaxCalculator()
+ + calculate(amount : double) : double
+ }
+ class ForeignTaxCalculator {
+ + TAX_PERCENTAGE : double {static}
+ + ForeignTaxCalculator()
+ + calculate(amount : double) : double
+ }
+}
+package com.iluwatar.separatedinterface.invoice {
+ class InvoiceGenerator {
+ - amount : double
+ - taxCalculator : TaxCalculator
+ + InvoiceGenerator(amount : double, taxCalculator : TaxCalculator)
+ + getAmountWithTax() : double
+ }
+ interface TaxCalculator {
+ + calculate(double) : double {abstract}
+ }
+}
+InvoiceGenerator --> "-taxCalculator" TaxCalculator
+DomesticTaxCalculator ..|> TaxCalculator
+ForeignTaxCalculator ..|> TaxCalculator
+@enduml
\ No newline at end of file
diff --git a/separated-interface/pom.xml b/separated-interface/pom.xml
new file mode 100644
index 000000000..c4d5f17f1
--- /dev/null
+++ b/separated-interface/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.24.0-SNAPSHOT
+
+ separated-interface
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.separatedinterface.App
+
+
+
+
+
+
+
+
+
diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java
new file mode 100644
index 000000000..f8884eda3
--- /dev/null
+++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/App.java
@@ -0,0 +1,60 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface;
+
+import com.iluwatar.separatedinterface.invoice.InvoiceGenerator;
+import com.iluwatar.separatedinterface.taxes.DomesticTaxCalculator;
+import com.iluwatar.separatedinterface.taxes.ForeignTaxCalculator;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ *
The Separated Interface pattern encourages to separate the interface definition and
+ * implementation in different packages. This allows the client to be completely unaware of the
+ * implementation.
+ *
+ * In this class the {@link InvoiceGenerator} class is injected with different instances of
+ * {@link com.iluwatar.separatedinterface.invoice.TaxCalculator} implementations located in separate
+ * packages, to receive different responses for both of the implementations.
+ */
+@Slf4j
+public class App {
+
+ public static final double PRODUCT_COST = 50.0;
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ //Create the invoice generator with product cost as 50 and foreign product tax
+ var internationalProductInvoice = new InvoiceGenerator(PRODUCT_COST,
+ new ForeignTaxCalculator());
+ LOGGER.info("Foreign Tax applied: {}", "" + internationalProductInvoice.getAmountWithTax());
+
+ //Create the invoice generator with product cost as 50 and domestic product tax
+ var domesticProductInvoice = new InvoiceGenerator(PRODUCT_COST, new DomesticTaxCalculator());
+ LOGGER.info("Domestic Tax applied: {}", "" + domesticProductInvoice.getAmountWithTax());
+ }
+}
diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java
new file mode 100644
index 000000000..fea32e2bf
--- /dev/null
+++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/InvoiceGenerator.java
@@ -0,0 +1,51 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface.invoice;
+
+/**
+ * InvoiceGenerator class generates an invoice, accepting the product cost and calculating the total
+ * price payable inclusive tax (calculated by {@link TaxCalculator}).
+ */
+public class InvoiceGenerator {
+
+ /**
+ * The TaxCalculator interface to calculate the payable tax.
+ */
+ private final TaxCalculator taxCalculator;
+
+ /**
+ * The base product amount without tax.
+ */
+ private final double amount;
+
+ public InvoiceGenerator(double amount, TaxCalculator taxCalculator) {
+ this.amount = amount;
+ this.taxCalculator = taxCalculator;
+ }
+
+ public double getAmountWithTax() {
+ return amount + taxCalculator.calculate(amount);
+ }
+
+}
\ No newline at end of file
diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/TaxCalculator.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/TaxCalculator.java
new file mode 100644
index 000000000..95deedf40
--- /dev/null
+++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/invoice/TaxCalculator.java
@@ -0,0 +1,30 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface.invoice;
+
+public interface TaxCalculator {
+
+ double calculate(double amount);
+
+}
diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculator.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculator.java
new file mode 100644
index 000000000..2018f281f
--- /dev/null
+++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculator.java
@@ -0,0 +1,40 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface.taxes;
+
+import com.iluwatar.separatedinterface.invoice.TaxCalculator;
+
+/**
+ * TaxCalculator for Domestic goods with 20% tax.
+ */
+public class DomesticTaxCalculator implements TaxCalculator {
+
+ public static final double TAX_PERCENTAGE = 20;
+
+ @Override
+ public double calculate(double amount) {
+ return amount * TAX_PERCENTAGE / 100.0;
+ }
+
+}
diff --git a/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculator.java b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculator.java
new file mode 100644
index 000000000..fcb45eb00
--- /dev/null
+++ b/separated-interface/src/main/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculator.java
@@ -0,0 +1,40 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface.taxes;
+
+import com.iluwatar.separatedinterface.invoice.TaxCalculator;
+
+/**
+ * TaxCalculator for foreign goods with 60% tax.
+ */
+public class ForeignTaxCalculator implements TaxCalculator {
+
+ public static final double TAX_PERCENTAGE = 60;
+
+ @Override
+ public double calculate(double amount) {
+ return amount * TAX_PERCENTAGE / 100.0;
+ }
+
+}
diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/AppTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/AppTest.java
new file mode 100644
index 000000000..1a09b49c8
--- /dev/null
+++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/AppTest.java
@@ -0,0 +1,41 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface;
+
+import org.junit.jupiter.api.Test;
+
+import com.iluwatar.separatedinterface.App;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+/**
+ * Application test.
+ */
+class AppTest {
+
+ @Test
+ void shouldExecuteWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
+ }
+}
diff --git a/semaphore/src/test/java/com/iluwatar/semaphore/FruitBowlTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java
similarity index 59%
rename from semaphore/src/test/java/com/iluwatar/semaphore/FruitBowlTest.java
rename to separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java
index bc21f9196..97455dfb6 100644
--- a/semaphore/src/test/java/com/iluwatar/semaphore/FruitBowlTest.java
+++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/invoice/InvoiceGeneratorTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -21,35 +21,31 @@
* THE SOFTWARE.
*/
-package com.iluwatar.semaphore;
+package com.iluwatar.separatedinterface.invoice;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-/**
- * Test taking from and putting Fruit into a FruitBowl
- */
-public class FruitBowlTest {
+class InvoiceGeneratorTest {
+
+ private InvoiceGenerator target;
@Test
- public void fruitBowlTest() {
- var fbowl = new FruitBowl();
+ void testGenerateTax() {
+ var productCost = 50.0;
+ var tax = 10.0;
+ TaxCalculator taxCalculatorMock = mock(TaxCalculator.class);
+ doReturn(tax).when(taxCalculatorMock).calculate(productCost);
- assertEquals(0, fbowl.countFruit());
+ target = new InvoiceGenerator(productCost, taxCalculatorMock);
- for (var i = 1; i <= 10; i++) {
- fbowl.put(new Fruit(Fruit.FruitType.LEMON));
- assertEquals(i, fbowl.countFruit());
- }
-
- for (var i = 9; i >= 0; i--) {
- assertNotNull(fbowl.take());
- assertEquals(i, fbowl.countFruit());
- }
-
- assertNull(fbowl.take());
+ Assertions.assertEquals(target.getAmountWithTax(), productCost + tax);
+ verify(taxCalculatorMock, times(1)).calculate(productCost);
}
+
}
diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculatorTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculatorTest.java
new file mode 100644
index 000000000..e06c407b8
--- /dev/null
+++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/DomesticTaxCalculatorTest.java
@@ -0,0 +1,41 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface.taxes;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class DomesticTaxCalculatorTest {
+
+ private DomesticTaxCalculator target;
+
+ @Test
+ void testTaxCalculation() {
+ target = new DomesticTaxCalculator();
+
+ var tax = target.calculate(100.0);
+ Assertions.assertEquals(tax, 20.0);
+ }
+
+}
diff --git a/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculatorTest.java b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculatorTest.java
new file mode 100644
index 000000000..ea05e4a7b
--- /dev/null
+++ b/separated-interface/src/test/java/com/iluwatar/separatedinterface/taxes/ForeignTaxCalculatorTest.java
@@ -0,0 +1,41 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.separatedinterface.taxes;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ForeignTaxCalculatorTest {
+
+ private ForeignTaxCalculator target;
+
+ @Test
+ void testTaxCalculation() {
+ target = new ForeignTaxCalculator();
+
+ var tax = target.calculate(100.0);
+ Assertions.assertEquals(tax, 60.0);
+ }
+
+}
diff --git a/servant/pom.xml b/servant/pom.xml
index 395060d50..cb8fd2089 100644
--- a/servant/pom.xml
+++ b/servant/pom.xml
@@ -2,7 +2,7 @@
"-instance" MaintenanceLock
+Db --> "-instance" Db
+ApplicationServicesImpl --> "-domain" DomainServicesImpl
+Account --+ Db
+ApplicationServicesImpl ..|> ApplicationServices
+DomainServicesImpl ..|> DomainServices
+DownForMaintenance ..|> ReceiptViewModel
+InsufficientFunds ..|> ReceiptViewModel
+InvalidUser ..|> ReceiptViewModel
+OutOfStock ..|> ReceiptViewModel
+ReceiptDto ..|> ReceiptViewModel
+@enduml
diff --git a/special-case/etc/special_case_urm.png b/special-case/etc/special_case_urm.png
new file mode 100644
index 000000000..03ca646f3
Binary files /dev/null and b/special-case/etc/special_case_urm.png differ
diff --git a/special-case/pom.xml b/special-case/pom.xml
new file mode 100644
index 000000000..5f6554068
--- /dev/null
+++ b/special-case/pom.xml
@@ -0,0 +1,46 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.24.0-SNAPSHOT
+
+ 4.0.0
+
+ special-case
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/App.java b/special-case/src/main/java/com/iluwatar/specialcase/App.java
new file mode 100644
index 000000000..02ae7b466
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/App.java
@@ -0,0 +1,70 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The Special Case Pattern is a software design pattern that encapsulates particular cases
+ * into subclasses that provide special behaviors.
+ *
+ * In this example ({@link ReceiptViewModel}) encapsulates all particular cases.
+ */
+public class App {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+
+ /**
+ * Program entry point.
+ */
+ public static void main(String[] args) {
+ // DB seeding
+ LOGGER.info("Db seeding: " + "1 user: {\"ignite1771\", amount = 1000.0}, "
+ + "2 products: {\"computer\": price = 800.0, \"car\": price = 20000.0}");
+ Db.getInstance().seedUser("ignite1771", 1000.0);
+ Db.getInstance().seedItem("computer", 800.0);
+ Db.getInstance().seedItem("car", 20000.0);
+
+ final var applicationServices = new ApplicationServicesImpl();
+ ReceiptViewModel receipt;
+
+ LOGGER.info("[REQUEST] User: " + "abc123" + " buy product: " + "tv");
+ receipt = applicationServices.loggedInUserPurchase("abc123", "tv");
+ receipt.show();
+ MaintenanceLock.getInstance().setLock(false);
+ LOGGER.info("[REQUEST] User: " + "abc123" + " buy product: " + "tv");
+ receipt = applicationServices.loggedInUserPurchase("abc123", "tv");
+ receipt.show();
+ LOGGER.info("[REQUEST] User: " + "ignite1771" + " buy product: " + "tv");
+ receipt = applicationServices.loggedInUserPurchase("ignite1771", "tv");
+ receipt.show();
+ LOGGER.info("[REQUEST] User: " + "ignite1771" + " buy product: " + "car");
+ receipt = applicationServices.loggedInUserPurchase("ignite1771", "car");
+ receipt.show();
+ LOGGER.info("[REQUEST] User: " + "ignite1771" + " buy product: " + "computer");
+ receipt = applicationServices.loggedInUserPurchase("ignite1771", "computer");
+ receipt.show();
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/ApplicationServices.java b/special-case/src/main/java/com/iluwatar/specialcase/ApplicationServices.java
new file mode 100644
index 000000000..e2b7acdde
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/ApplicationServices.java
@@ -0,0 +1,29 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+public interface ApplicationServices {
+
+ ReceiptViewModel loggedInUserPurchase(String userName, String itemName);
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/ApplicationServicesImpl.java b/special-case/src/main/java/com/iluwatar/specialcase/ApplicationServicesImpl.java
new file mode 100644
index 000000000..eebd6dbc0
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/ApplicationServicesImpl.java
@@ -0,0 +1,41 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+public class ApplicationServicesImpl implements ApplicationServices {
+
+ private DomainServicesImpl domain = new DomainServicesImpl();
+
+ @Override
+ public ReceiptViewModel loggedInUserPurchase(String userName, String itemName) {
+ if (isDownForMaintenance()) {
+ return new DownForMaintenance();
+ }
+ return this.domain.purchase(userName, itemName);
+ }
+
+ private boolean isDownForMaintenance() {
+ return MaintenanceLock.getInstance().isLock();
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/Db.java b/special-case/src/main/java/com/iluwatar/specialcase/Db.java
new file mode 100644
index 000000000..a456dd2c4
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/Db.java
@@ -0,0 +1,170 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Db {
+
+ private static Db instance;
+ private Map userName2User;
+ private Map user2Account;
+ private Map itemName2Product;
+
+ /**
+ * Get the instance of Db.
+ *
+ * @return singleton instance of Db class
+ */
+ public static synchronized Db getInstance() {
+ if (instance == null) {
+ Db newInstance = new Db();
+ newInstance.userName2User = new HashMap<>();
+ newInstance.user2Account = new HashMap<>();
+ newInstance.itemName2Product = new HashMap<>();
+ instance = newInstance;
+ }
+ return instance;
+ }
+
+ /**
+ * Seed a user into Db.
+ *
+ * @param userName of the user
+ * @param amount of the user's account
+ */
+ public void seedUser(String userName, Double amount) {
+ User user = new User(userName);
+ instance.userName2User.put(userName, user);
+ Account account = new Account(amount);
+ instance.user2Account.put(user, account);
+ }
+
+ /**
+ * Seed an item into Db.
+ *
+ * @param itemName of the item
+ * @param price of the item
+ */
+ public void seedItem(String itemName, Double price) {
+ Product item = new Product(price);
+ itemName2Product.put(itemName, item);
+ }
+
+ /**
+ * Find a user with the userName.
+ *
+ * @param userName of the user
+ * @return instance of User
+ */
+ public User findUserByUserName(String userName) {
+ if (!userName2User.containsKey(userName)) {
+ return null;
+ }
+ return userName2User.get(userName);
+ }
+
+ /**
+ * Find an account of the user.
+ *
+ * @param user in Db
+ * @return instance of Account of the user
+ */
+ public Account findAccountByUser(User user) {
+ if (!user2Account.containsKey(user)) {
+ return null;
+ }
+ return user2Account.get(user);
+ }
+
+ /**
+ * Find a product with the itemName.
+ *
+ * @param itemName of the item
+ * @return instance of Product
+ */
+ public Product findProductByItemName(String itemName) {
+ if (!itemName2Product.containsKey(itemName)) {
+ return null;
+ }
+ return itemName2Product.get(itemName);
+ }
+
+ public class User {
+
+ private String userName;
+
+ public User(String userName) {
+ this.userName = userName;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public ReceiptDto purchase(Product item) {
+ return new ReceiptDto(item.getPrice());
+ }
+ }
+
+ public class Account {
+
+ private Double amount;
+
+ public Account(Double amount) {
+ this.amount = amount;
+ }
+
+ /**
+ * Withdraw the price of the item from the account.
+ *
+ * @param price of the item
+ * @return instance of MoneyTransaction
+ */
+ public MoneyTransaction withdraw(Double price) {
+ if (price > amount) {
+ return null;
+ }
+ return new MoneyTransaction(amount, price);
+ }
+
+ public Double getAmount() {
+ return amount;
+ }
+ }
+
+ public class Product {
+
+ private Double price;
+
+ public Product(Double price) {
+ this.price = price;
+ }
+
+ public Double getPrice() {
+ return price;
+ }
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/DomainServices.java b/special-case/src/main/java/com/iluwatar/specialcase/DomainServices.java
new file mode 100644
index 000000000..cd09af916
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/DomainServices.java
@@ -0,0 +1,27 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+public interface DomainServices {
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/DomainServicesImpl.java b/special-case/src/main/java/com/iluwatar/specialcase/DomainServicesImpl.java
new file mode 100644
index 000000000..22beab8b9
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/DomainServicesImpl.java
@@ -0,0 +1,69 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+public class DomainServicesImpl implements DomainServices {
+
+ /**
+ * Domain purchase with userName and itemName, with validation for userName.
+ *
+ * @param userName of the user
+ * @param itemName of the item
+ * @return instance of ReceiptViewModel
+ */
+ public ReceiptViewModel purchase(String userName, String itemName) {
+ Db.User user = Db.getInstance().findUserByUserName(userName);
+ if (user == null) {
+ return new InvalidUser(userName);
+ }
+
+ Db.Account account = Db.getInstance().findAccountByUser(user);
+ return purchase(user, account, itemName);
+ }
+
+ /**
+ * Domain purchase with user, account and itemName,
+ * with validation for whether product is out of stock
+ * and whether user has insufficient funds in the account.
+ *
+ * @param user in Db
+ * @param account in Db
+ * @param itemName of the item
+ * @return instance of ReceiptViewModel
+ */
+ private ReceiptViewModel purchase(Db.User user, Db.Account account, String itemName) {
+ Db.Product item = Db.getInstance().findProductByItemName(itemName);
+ if (item == null) {
+ return new OutOfStock(user.getUserName(), itemName);
+ }
+
+ ReceiptDto receipt = user.purchase(item);
+ MoneyTransaction transaction = account.withdraw(receipt.getPrice());
+ if (transaction == null) {
+ return new InsufficientFunds(user.getUserName(), account.getAmount(), itemName);
+ }
+
+ return receipt;
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/DownForMaintenance.java b/special-case/src/main/java/com/iluwatar/specialcase/DownForMaintenance.java
new file mode 100644
index 000000000..a0348663d
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/DownForMaintenance.java
@@ -0,0 +1,37 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DownForMaintenance implements ReceiptViewModel {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DownForMaintenance.class);
+
+ @Override
+ public void show() {
+ LOGGER.info("Down for maintenance");
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/InsufficientFunds.java b/special-case/src/main/java/com/iluwatar/specialcase/InsufficientFunds.java
new file mode 100644
index 000000000..32e373d2a
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/InsufficientFunds.java
@@ -0,0 +1,53 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class InsufficientFunds implements ReceiptViewModel {
+
+ private String userName;
+ private Double amount;
+ private String itemName;
+
+ /**
+ * Constructor of InsufficientFunds.
+ *
+ * @param userName of the user
+ * @param amount of the user's account
+ * @param itemName of the item
+ */
+ public InsufficientFunds(String userName, Double amount, String itemName) {
+ this.userName = userName;
+ this.amount = amount;
+ this.itemName = itemName;
+ }
+
+ @Override
+ public void show() {
+ LOGGER.info("Insufficient funds: " + amount + " of user: " + userName
+ + " for buying item: " + itemName);
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/InvalidUser.java b/special-case/src/main/java/com/iluwatar/specialcase/InvalidUser.java
new file mode 100644
index 000000000..ac1abfd67
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/InvalidUser.java
@@ -0,0 +1,43 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InvalidUser implements ReceiptViewModel {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(InvalidUser.class);
+
+ private final String userName;
+
+ public InvalidUser(String userName) {
+ this.userName = userName;
+ }
+
+ @Override
+ public void show() {
+ LOGGER.info("Invalid user: " + userName);
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/MaintenanceLock.java b/special-case/src/main/java/com/iluwatar/specialcase/MaintenanceLock.java
new file mode 100644
index 000000000..e22a96096
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/MaintenanceLock.java
@@ -0,0 +1,56 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MaintenanceLock {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MaintenanceLock.class);
+
+ private static MaintenanceLock instance;
+ private boolean lock = true;
+
+ /**
+ * Get the instance of MaintenanceLock.
+ *
+ * @return singleton instance of MaintenanceLock
+ */
+ public static synchronized MaintenanceLock getInstance() {
+ if (instance == null) {
+ instance = new MaintenanceLock();
+ }
+ return instance;
+ }
+
+ public boolean isLock() {
+ return lock;
+ }
+
+ public void setLock(boolean lock) {
+ this.lock = lock;
+ LOGGER.info("Maintenance lock is set to: ", lock);
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/MoneyTransaction.java b/special-case/src/main/java/com/iluwatar/specialcase/MoneyTransaction.java
new file mode 100644
index 000000000..260a765d2
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/MoneyTransaction.java
@@ -0,0 +1,35 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+public class MoneyTransaction {
+
+ private Double amount;
+ private Double price;
+
+ public MoneyTransaction(Double amount, Double price) {
+ this.amount = amount;
+ this.price = price;
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/OutOfStock.java b/special-case/src/main/java/com/iluwatar/specialcase/OutOfStock.java
new file mode 100644
index 000000000..2b3cbbab7
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/OutOfStock.java
@@ -0,0 +1,45 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OutOfStock implements ReceiptViewModel {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(OutOfStock.class);
+
+ private String userName;
+ private String itemName;
+
+ public OutOfStock(String userName, String itemName) {
+ this.userName = userName;
+ this.itemName = itemName;
+ }
+
+ @Override
+ public void show() {
+ LOGGER.info("Out of stock: " + itemName + " for user = " + userName + " to buy");
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/ReceiptDto.java b/special-case/src/main/java/com/iluwatar/specialcase/ReceiptDto.java
new file mode 100644
index 000000000..304241f73
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/ReceiptDto.java
@@ -0,0 +1,47 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ReceiptDto implements ReceiptViewModel {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ReceiptDto.class);
+
+ private Double price;
+
+ public ReceiptDto(Double price) {
+ this.price = price;
+ }
+
+ public Double getPrice() {
+ return price;
+ }
+
+ @Override
+ public void show() {
+ LOGGER.info("Receipt: " + price + " paid");
+ }
+}
diff --git a/special-case/src/main/java/com/iluwatar/specialcase/ReceiptViewModel.java b/special-case/src/main/java/com/iluwatar/specialcase/ReceiptViewModel.java
new file mode 100644
index 000000000..d50408dae
--- /dev/null
+++ b/special-case/src/main/java/com/iluwatar/specialcase/ReceiptViewModel.java
@@ -0,0 +1,29 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+public interface ReceiptViewModel {
+
+ void show();
+}
diff --git a/special-case/src/test/java/com/iluwatar/specialcase/AppTest.java b/special-case/src/test/java/com/iluwatar/specialcase/AppTest.java
new file mode 100644
index 000000000..4c85849cb
--- /dev/null
+++ b/special-case/src/test/java/com/iluwatar/specialcase/AppTest.java
@@ -0,0 +1,39 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Application test.
+ */
+public class AppTest {
+
+ @Test
+ void shouldExecuteWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
+ }
+}
diff --git a/special-case/src/test/java/com/iluwatar/specialcase/SpecialCasesTest.java b/special-case/src/test/java/com/iluwatar/specialcase/SpecialCasesTest.java
new file mode 100644
index 000000000..4504057c4
--- /dev/null
+++ b/special-case/src/test/java/com/iluwatar/specialcase/SpecialCasesTest.java
@@ -0,0 +1,143 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 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.specialcase;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.slf4j.LoggerFactory;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+
+/**
+ * Special cases unit tests. (including the successful scenario {@link ReceiptDto})
+ */
+public class SpecialCasesTest {
+ private static ApplicationServices applicationServices;
+ private static ReceiptViewModel receipt;
+
+ @BeforeAll
+ static void beforeAll() {
+ Db.getInstance().seedUser("ignite1771", 1000.0);
+ Db.getInstance().seedItem("computer", 800.0);
+ Db.getInstance().seedItem("car", 20000.0);
+
+ applicationServices = new ApplicationServicesImpl();
+ }
+
+ @BeforeEach
+ public void beforeEach() {
+ MaintenanceLock.getInstance().setLock(false);
+ }
+
+ @Test
+ public void testDownForMaintenance() {
+ final Logger LOGGER = (Logger) LoggerFactory.getLogger(DownForMaintenance.class);
+
+ ListAppender listAppender = new ListAppender<>();
+ listAppender.start();
+ LOGGER.addAppender(listAppender);
+
+ MaintenanceLock.getInstance().setLock(true);
+ receipt = applicationServices.loggedInUserPurchase(null, null);
+ receipt.show();
+
+ List loggingEventList = listAppender.list;
+ assertEquals("Down for maintenance", loggingEventList.get(0).getMessage());
+ assertEquals(Level.INFO, loggingEventList.get(0).getLevel());
+ }
+
+ @Test
+ public void testInvalidUser() {
+ final Logger LOGGER = (Logger) LoggerFactory.getLogger(InvalidUser.class);
+
+ ListAppender listAppender = new ListAppender<>();
+ listAppender.start();
+ LOGGER.addAppender(listAppender);
+
+ receipt = applicationServices.loggedInUserPurchase("a", null);
+ receipt.show();
+
+ List loggingEventList = listAppender.list;
+ assertEquals("Invalid user: a", loggingEventList.get(0).getMessage());
+ assertEquals(Level.INFO, loggingEventList.get(0).getLevel());
+ }
+
+ @Test
+ public void testOutOfStock() {
+ final Logger LOGGER = (Logger) LoggerFactory.getLogger(OutOfStock.class);
+
+ ListAppender listAppender = new ListAppender<>();
+ listAppender.start();
+ LOGGER.addAppender(listAppender);
+
+ receipt = applicationServices.loggedInUserPurchase("ignite1771", "tv");
+ receipt.show();
+
+ List loggingEventList = listAppender.list;
+ assertEquals("Out of stock: tv for user = ignite1771 to buy"
+ , loggingEventList.get(0).getMessage());
+ assertEquals(Level.INFO, loggingEventList.get(0).getLevel());
+ }
+
+ @Test
+ public void testInsufficientFunds() {
+ final Logger LOGGER = (Logger) LoggerFactory.getLogger(InsufficientFunds.class);
+
+ ListAppender listAppender = new ListAppender<>();
+ listAppender.start();
+ LOGGER.addAppender(listAppender);
+
+ receipt = applicationServices.loggedInUserPurchase("ignite1771", "car");
+ receipt.show();
+
+ List loggingEventList = listAppender.list;
+ assertEquals("Insufficient funds: 1000.0 of user: ignite1771 for buying item: car"
+ , loggingEventList.get(0).getMessage());
+ assertEquals(Level.INFO, loggingEventList.get(0).getLevel());
+ }
+
+ @Test
+ public void testReceiptDto() {
+ final Logger LOGGER = (Logger) LoggerFactory.getLogger(ReceiptDto.class);
+
+ ListAppender listAppender = new ListAppender<>();
+ listAppender.start();
+ LOGGER.addAppender(listAppender);
+
+ receipt = applicationServices.loggedInUserPurchase("ignite1771", "computer");
+ receipt.show();
+
+ List loggingEventList = listAppender.list;
+ assertEquals("Receipt: 800.0 paid"
+ , loggingEventList.get(0).getMessage());
+ assertEquals(Level.INFO, loggingEventList.get(0).getLevel());
+ }
+}
diff --git a/specification/README.md b/specification/README.md
index 6cc0c702f..5648a73b0 100644
--- a/specification/README.md
+++ b/specification/README.md
@@ -9,36 +9,46 @@ tags:
---
## Also known as
+
Filter, Criteria
## Intent
-Specification pattern separates the statement of how to match a
-candidate, from the candidate object that it is matched against. As well as its
-usefulness in selection, it is also valuable for validation and for building to
-order.
+
+Specification pattern separates the statement of how to match a candidate, from the candidate object
+that it is matched against. As well as its usefulness in selection, it is also valuable for
+validation and for building to order.
## Explanation
Real world example
-> There is a pool of different creatures and we often need to select some subset of them.
-> We can write our search specification such as "creatures that can fly", "creatures heavier than 500 kilograms", or as a combination of other search specifications, and then give it to the party that will perform the filtering.
+> There is a pool of different creatures and we often need to select some subset of them. We can
+> write our search specification such as "creatures that can fly", "creatures heavier than 500
+> kilograms", or as a combination of other search specifications, and then give it to the party that
+> will perform the filtering.
In Plain Words
-> Specification pattern allows us to separate the search criteria from the object that performs the search.
+> Specification pattern allows us to separate the search criteria from the object that performs the
+> search.
Wikipedia says
-> In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic.
+> In computer programming, the specification pattern is a particular software design pattern,
+> whereby business rules can be recombined by chaining the business rules together using boolean
+> logic.
**Programmatic Example**
-If we look at our creature pool example from above, we have a set of creatures with certain properties.
-Those properties can be part of a pre-defined, limited set (represented here by the enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a Creature).
-In this case, it is more appropriate to use what we call "parameterized specification", where the property value can be given as an argument when the Creature is instantiated, allowing for more flexibility.
-A third option is to combine pre-defined and/or parameterized properties using boolean logic, allowing for near-endless selection possibilities (this is called "composite specification", see below).
-The pros and cons of each approach are detailed in the table at the end of this document.
+If we look at our creature pool example from above, we have a set of creatures with certain
+properties. Those properties can be part of a pre-defined, limited set (represented here by the
+enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a
+Creature). In this case, it is more appropriate to use what we call "parameterized specification",
+where the property value can be given as an argument when the Creature is instantiated, allowing for
+more flexibility. A third option is to combine pre-defined and/or parameterized properties using
+boolean logic, allowing for near-endless selection possibilities (this is called "composite
+specification", see below). The pros and cons of each approach are detailed in the table at the end
+of this document.
```java
public interface Creature {
@@ -50,7 +60,7 @@ public interface Creature {
}
```
-And ``Dragon`` implementation looks like this.
+And `Dragon` implementation looks like this.
```java
public class Dragon extends AbstractCreature {
@@ -61,7 +71,8 @@ public class Dragon extends AbstractCreature {
}
```
-Now that we want to select some subset of them, we use selectors. To select creatures that fly, we should use ``MovementSelector``.
+Now that we want to select some subset of them, we use selectors. To select creatures that fly, we
+should use `MovementSelector`.
```java
public class MovementSelector extends AbstractSelector {
@@ -79,7 +90,8 @@ public class MovementSelector extends AbstractSelector {
}
```
-On the other hand, when selecting creatures heavier than a chosen amount, we use ``MassGreaterThanSelector``.
+On the other hand, when selecting creatures heavier than a chosen amount, we use
+`MassGreaterThanSelector`.
```java
public class MassGreaterThanSelector extends AbstractSelector {
@@ -111,7 +123,8 @@ But we could also use our parameterized selector like this:
.collect(Collectors.toList());
```
-Our third option is to combine multiple selectors together. Performing a search for special creatures (defined as red, flying, and not small) could be done as follows:
+Our third option is to combine multiple selectors together. Performing a search for special
+creatures (defined as red, flying, and not small) could be done as follows:
```java
var specialCreaturesSelector =
@@ -123,8 +136,9 @@ Our third option is to combine multiple selectors together. Performing a search
**More on Composite Specification**
-In Composite Specification, we will create custom instances of ``AbstractSelector`` by combining other selectors (called "leaves") using the three basic logical operators.
-These are implemented in ``ConjunctionSelector``, ``DisjunctionSelector`` and ``NegationSelector``.
+In Composite Specification, we will create custom instances of `AbstractSelector` by combining
+other selectors (called "leaves") using the three basic logical operators. These are implemented in
+`ConjunctionSelector`, `DisjunctionSelector` and `NegationSelector`.
```java
public abstract class AbstractSelector implements Predicate {
@@ -163,12 +177,14 @@ public class ConjunctionSelector extends AbstractSelector {
}
```
-All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that are as generic as possible,
-and we will be able to instantiate the ``AbstractSelector`` class by combining any amount of selectors, as exemplified above.
-We should be careful though, as it is easy to make a mistake when combining many logical operators; in particular, we should pay attention to the priority of the operations.\
-In general, Composite Specification is a great way to write more reusable code, as there is no need to create a Selector class for each filtering operation.
-Instead, we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf" selectors and some basic boolean logic.
-
+All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that
+are as generic as possible, and we will be able to instantiate the ``AbstractSelector`` class by
+combining any amount of selectors, as exemplified above. We should be careful though, as it is easy
+to make a mistake when combining many logical operators; in particular, we should pay attention to
+the priority of the operations. In general, Composite Specification is a great way to write more
+reusable code, as there is no need to create a Selector class for each filtering operation. Instead,
+we just create an instance of ``AbstractSelector`` "on the spot", using tour generic "leaf"
+selectors and some basic boolean logic.
**Comparison of the different approaches**
@@ -181,9 +197,11 @@ Instead, we just create an instance of ``AbstractSelector`` "on the spot", using
| | | + Supports logical operations | - You still need to create the base classes used as leaves |
## Class diagram
+

## Applicability
+
Use the Specification pattern when
* You need to select a subset of objects based on some criteria, and to refresh the selection at various times.
diff --git a/specification/pom.xml b/specification/pom.xml
index 9214e984e..4f0250bea 100644
--- a/specification/pom.xml
+++ b/specification/pom.xml
@@ -2,7 +2,7 @@
"-dragonSlayingStrategy" DragonSlayingStrategy
DragonSlayer --> "-strategy" DragonSlayingStrategy
+Strategy ..|> DragonSlayingStrategy
MeleeStrategy ..|> DragonSlayingStrategy
ProjectileStrategy ..|> DragonSlayingStrategy
SpellStrategy ..|> DragonSlayingStrategy
diff --git a/strategy/etc/strategy_1.png b/strategy/etc/strategy_1.png
deleted file mode 100644
index c341e58c6..000000000
Binary files a/strategy/etc/strategy_1.png and /dev/null differ
diff --git a/strategy/etc/strategy_urm.png b/strategy/etc/strategy_urm.png
new file mode 100644
index 000000000..67d19acae
Binary files /dev/null and b/strategy/etc/strategy_urm.png differ
diff --git a/strategy/pom.xml b/strategy/pom.xml
index cd1395c7a..9e2e0c75f 100644
--- a/strategy/pom.xml
+++ b/strategy/pom.xml
@@ -2,7 +2,7 @@
+
+
+[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
+[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
+[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
+[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+[](#contributors-)
+
+
+# Giriş
+
+Tasarım desenleri, bir yazılım mühendisi bir uygulamayı veya sistemi tasarlarken yaygın sorunları çözmek için kullanabileceği en iyi çözüm prensipleridir.
+
+Tasarım desenleri, test edilip kanıtlanmış prensipler olduğu için yazılım geliştirme sürecini hızlandırabilir.
+
+Tasarım desenlerini yeniden kullanmak, büyük sorunlara neden olan ince sorunları önlemeye yardımcı olur ve aynı zamanda tasarım desenlerine alışkın olan yazılım mühendisileri ve yazılım mimarları için kod okunabilirliğini artırır.
+
+# Başlangıç
+
+Bu site Java Tasarım Desenlerini sergiliyor. Çözümler, açık kaynak topluluğundan deneyimli yazılım mühendisileri ve yazılım mimarları tarafından geliştirilmiştir. Bu yazılım desenleri, detaylı açıklamalarıyla veya kaynak kodlarına bakılarak göz atılabilir. Kaynak kod örneklerinde iyi derecede açıklayıcı yorum satırlarına sahip olup ve belirli bir tasarım deseninin nasıl uygulanacağına dair programlama dersi olarak düşünülebilir. Savaşta en çok kanıtlanmış açık kaynak Java teknolojilerini kullanıyoruz.
+
+Bu projeye başlamadan önce çeşitli [Yazılım Tasarım İlkelerine](https://java-design-patterns.com/principles/) aşina olmalısınız.
+
+Tüm tasarımlar olabildiğince basit olmalıdır. [KISS](https://en.wikipedia.org/wiki/KISS_principle), [YAGNI](https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it) ve [Do The Simplest Thing That Could Possibly Work](https://learning.oreilly.com/library/view/extreme-programming-pocket/9781449399849/ch17.html) ilkeleri ile başlamalısınız.
+
+Bu kavramlara aşina olduktan sonra, aşağıdaki yaklaşımlardan herhangi birini kullanarak [mevcut tasarım desenlerini](https://java-design-patterns.com/patterns/) derinlemesine incelemeye başlayabilirsiniz.
+
+- İsme göre belirli bir tasarım deseni arayın. Bulamadınız mı? Lütfen yeni bir tasarım deseni için [bizim ile](https://github.com/iluwatar/java-design-patterns/issues) iletişime geçin.
+- Performance, Gang of Four ya da Data access gibi etiketleri kullanın.
+- Creational(Yaratıcı Tasarım Desenleri), Behavioral(Davranışsal Tasarım Desenleri), ve Structural(Yapısal Tasarım Desenleri) gibi tasarım kategorilerini kullanın.
+
+Umarım bu sitede sunulan nesne yönelimli çözümleri yazılım mimarileriniz için yararlı bulursunuz ve onları geliştirirken bizim kadar eğlenirsiniz.
+
+# Nasıl Katkı Sağlayabilirim
+
+Projeye katkıda bulunmaya istekliysen, ilgili bilgileri [geliştirici wiki'mizde](https://github.com/iluwatar/java-design-patterns/wiki) bulabilirsin. [Gitter](https://gitter.im/iluwatar/java-design-patterns) ile size yardımcı olacağız ve sorularınızı cevaplayacağız.
+
+# Lisans
+
+Bu proje, MIT lisansı koşulları altında lisanslanmıştır.
diff --git a/tr/singleton/README.md b/tr/singleton/README.md
new file mode 100644
index 000000000..2f6d494e8
--- /dev/null
+++ b/tr/singleton/README.md
@@ -0,0 +1,87 @@
+---
+layout: pattern
+title: Singleton
+folder: singleton
+permalink: /patterns/singleton/
+categories: Creational
+tags:
+- Gang of Four
+---
+
+## Amaç
+
+Bir sınıfın yalnızca bir örneğine sahip olduğundan emin olun ve ona global bir erişim noktası sağlayın.
+
+
+## Açıklama
+
+Örnek
+
+> Büyücülerin büyülerini çalıstıkları tek bir fildişi kule olabilir. Aynı büyülü fildişi kule,
+> büyücüler tarafından her zaman kullanılır. Buradaki fildişi kulesi singleton tasarım desenine örnektir.
+Özetle
+
+> Belirli bir sınıftan yalnızca bir nesnenin oluşturulmasını sağlar.
+Wikipedia açıklaması
+
+
+
+> Yazılım mühendisliğinde, tekil desen, bir sınıfın somutlaştırılmasını tek bir nesneyle sınırlayan
+> bir yazılım tasarım modelidir.Bu,sistemdeki eylemleri koordine etmek için
+> tam olarak bir nesne gerektiğinde kullanışlıdır.
+**Örnek**
+
+Joshua Bloch, Effective Java 2nd Edition p.18
+
+> Enum singleton tasarım desenini uygulamak için en iyi yoldur.
+```java
+public enum EnumIvoryTower {
+ INSTANCE
+}
+```
+
+Tanımladıktan sonra kullanmak için:
+
+```java
+var enumIvoryTower1 = EnumIvoryTower.INSTANCE;
+var enumIvoryTower2 = EnumIvoryTower.INSTANCE;
+assertEquals(enumIvoryTower1, enumIvoryTower2); // true
+```
+
+## Sınıf diagramı
+
+
+
+## Uygulanabilirlik
+
+Singleton tasarım deseni şu durumlarda kullanılmalıdır
+
+* Bir sınıfın tam olarak bir örneği olmalı ve iyi bilinen bir erişim noktasından istemciler tarafından erişilebilir olmalıdır.
+* Tek örnek alt sınıflandırma yoluyla genişletilebilir olduğunda ve istemciler, kodlarını değiştirmeden genişletilmiş bir örnek kullanabilmelidir
+
+## Use Case
+
+* Logging sınıflarında
+* Database bağlantılarını yönetmek için
+* File manager
+
+## Gerçek dünya örnekleri
+
+* [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
+* [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--)
+* [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)
+
+
+## Sonuçlar
+
+* Kendi yaratımını ve yaşam döngüsünü kontrol ederek Tek Sorumluluk İlkesini (SRP) ihlal ediyor.
+* Bu nesne tarafından kullanılan bir nesnenin ve kaynakların serbest bırakılmasını önleyen global bir paylaşılan örnek kullanmayı teşvik eder.
+* Birbirine sıkı bağlı kod oluşturur. Singleton tasarım deseni kullanan istemci sınıflarını test etmek zorlaşır.
+* Bir Singleton tasarım deseninden alt sınıflar oluşturmak neredeyse imkansız hale gelir.
+
+## 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)
+* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb)
+* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
+* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
\ No newline at end of file
diff --git a/trampoline/README.md b/trampoline/README.md
index 8831f41e1..d2ff7386b 100644
--- a/trampoline/README.md
+++ b/trampoline/README.md
@@ -10,22 +10,23 @@ 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.
+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
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.
+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.
+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.
+Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the
+stack.
Real world example
@@ -37,14 +38,18 @@ In plain words
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.
+> 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`.
+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 {
@@ -110,15 +115,21 @@ Using the `Trampoline` to get Fibonacci values.
log.info("start pattern");
var result = loop(10, 1).result();
log.info("result {}", result);
-
- // start pattern
- // result 3628800
+```
+
+Program output:
+
+```
+start pattern
+result 3628800
```
## Class diagram
+

## Applicability
+
Use the Trampoline pattern when
* For implementing tail recursive function. This pattern allows to switch on a stackless operation.
diff --git a/trampoline/pom.xml b/trampoline/pom.xml
index 13988ca92..48b501be6 100644
--- a/trampoline/pom.xml
+++ b/trampoline/pom.xml
@@ -2,7 +2,7 @@
+ The MIT License
+ Copyright © 2014-2021 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.
+
+-->
java-design-patterns
com.iluwatar
- 1.23.0-SNAPSHOT
+ 1.24.0-SNAPSHOT
4.0.0
update-method
- junit
- junit
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
diff --git a/update-method/src/main/java/com/iluwatar/updatemethod/App.java b/update-method/src/main/java/com/iluwatar/updatemethod/App.java
index 45069a3de..b036a0cb2 100644
--- a/update-method/src/main/java/com/iluwatar/updatemethod/App.java
+++ b/update-method/src/main/java/com/iluwatar/updatemethod/App.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,8 +23,7 @@
package com.iluwatar.updatemethod;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* This pattern simulate a collection of independent objects by telling each to
@@ -32,10 +31,9 @@ import org.slf4j.LoggerFactory;
* of objects. Each object implements an update method that simulates one frame of
* the object’s behavior. Each frame, the game updates every object in the collection.
*/
+@Slf4j
public class App {
- private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
-
private static final int GAME_RUNNING_TIME = 2000;
/**
diff --git a/update-method/src/main/java/com/iluwatar/updatemethod/Entity.java b/update-method/src/main/java/com/iluwatar/updatemethod/Entity.java
index 0f10d7775..9033c804a 100644
--- a/update-method/src/main/java/com/iluwatar/updatemethod/Entity.java
+++ b/update-method/src/main/java/com/iluwatar/updatemethod/Entity.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,6 +23,8 @@
package com.iluwatar.updatemethod;
+import lombok.Getter;
+import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,6 +37,8 @@ public abstract class Entity {
protected int id;
+ @Getter
+ @Setter
protected int position;
public Entity(int id) {
@@ -44,11 +48,4 @@ public abstract class Entity {
public abstract void update();
- public int getPosition() {
- return position;
- }
-
- public void setPosition(int position) {
- this.position = position;
- }
}
diff --git a/update-method/src/main/java/com/iluwatar/updatemethod/Skeleton.java b/update-method/src/main/java/com/iluwatar/updatemethod/Skeleton.java
index e365d6aec..5e0ed27ac 100644
--- a/update-method/src/main/java/com/iluwatar/updatemethod/Skeleton.java
+++ b/update-method/src/main/java/com/iluwatar/updatemethod/Skeleton.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -51,9 +51,9 @@ public class Skeleton extends Entity {
* Constructor of Skeleton.
*
* @param id id of skeleton
- * @param postition position of skeleton
+ * @param position position of skeleton
*/
- public Skeleton(int id, int postition) {
+ public Skeleton(int id, int position) {
super(id);
this.position = position;
patrollingLeft = false;
@@ -72,7 +72,7 @@ public class Skeleton extends Entity {
patrollingLeft = true;
}
}
- logger.info("Skeleton " + id + " is on position " + position + ".");
+ logger.info("Skeleton {} is on position {}.", id, position);
}
}
diff --git a/update-method/src/main/java/com/iluwatar/updatemethod/Statue.java b/update-method/src/main/java/com/iluwatar/updatemethod/Statue.java
index f1f3e2a87..eac4cbd00 100644
--- a/update-method/src/main/java/com/iluwatar/updatemethod/Statue.java
+++ b/update-method/src/main/java/com/iluwatar/updatemethod/Statue.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -57,7 +57,7 @@ public class Statue extends Entity {
@Override
public void update() {
- if (++ frames == delay) {
+ if (++frames == delay) {
shootLightning();
frames = 0;
}
diff --git a/update-method/src/main/java/com/iluwatar/updatemethod/World.java b/update-method/src/main/java/com/iluwatar/updatemethod/World.java
index 5b99050c8..f4a86cec2 100644
--- a/update-method/src/main/java/com/iluwatar/updatemethod/World.java
+++ b/update-method/src/main/java/com/iluwatar/updatemethod/World.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,20 +23,18 @@
package com.iluwatar.updatemethod;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
/**
* The game world class. Maintain all the objects existed in the game frames.
*/
+@Slf4j
public class World {
- private static final Logger LOGGER = LoggerFactory.getLogger(World.class);
-
protected List entities;
protected volatile boolean isRunning;
@@ -66,10 +64,11 @@ public class World {
*/
private void processInput() {
try {
- int lag = new Random().nextInt(200) + 50;
+ int lag = new SecureRandom().nextInt(200) + 50;
Thread.sleep(lag);
} catch (InterruptedException e) {
LOGGER.error(e.getMessage());
+ Thread.currentThread().interrupt();
}
}
@@ -88,6 +87,7 @@ public class World {
* pattern.
*/
private void render() {
+ // Does Nothing
}
/**
diff --git a/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java b/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java
index 75c30470d..b7590ec9b 100644
--- a/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java
+++ b/update-method/src/test/java/com/iluwatar/updatemethod/AppTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,13 +23,14 @@
package com.iluwatar.updatemethod;
-import org.junit.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-public class AppTest {
+import org.junit.jupiter.api.Test;
+
+class AppTest {
@Test
- public void testMain() {
- String[] args = {};
- App.main(args);
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
}
}
diff --git a/update-method/src/test/java/com/iluwatar/updatemethod/SkeletonTest.java b/update-method/src/test/java/com/iluwatar/updatemethod/SkeletonTest.java
index 73ab9eb1d..620dfde73 100644
--- a/update-method/src/test/java/com/iluwatar/updatemethod/SkeletonTest.java
+++ b/update-method/src/test/java/com/iluwatar/updatemethod/SkeletonTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,56 +23,59 @@
package com.iluwatar.updatemethod;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
-public class SkeletonTest {
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
- private Skeleton skeleton;
+class SkeletonTest {
- @Before
- public void setup() {
+ private static Skeleton skeleton;
+
+ @BeforeAll
+ public static void setup() {
skeleton = new Skeleton(1);
}
- @After
- public void tearDown() {
+ @AfterAll
+ public static void tearDown() {
skeleton = null;
}
@Test
- public void testUpdateForPatrollingLeft() {
+ void testUpdateForPatrollingLeft() {
skeleton.patrollingLeft = true;
skeleton.setPosition(50);
skeleton.update();
- Assert.assertEquals(49, skeleton.getPosition());
+ assertEquals(49, skeleton.getPosition());
}
@Test
- public void testUpdateForPatrollingRight() {
+ void testUpdateForPatrollingRight() {
skeleton.patrollingLeft = false;
skeleton.setPosition(50);
skeleton.update();
- Assert.assertEquals(51, skeleton.getPosition());
+ assertEquals(51, skeleton.getPosition());
}
@Test
- public void testUpdateForReverseDirectionFromLeftToRight() {
+ void testUpdateForReverseDirectionFromLeftToRight() {
skeleton.patrollingLeft = true;
skeleton.setPosition(1);
skeleton.update();
- Assert.assertEquals(0, skeleton.getPosition());
- Assert.assertEquals(false, skeleton.patrollingLeft);
+ assertEquals(0, skeleton.getPosition());
+ assertFalse(skeleton.patrollingLeft);
}
@Test
- public void testUpdateForReverseDirectionFromRightToLeft() {
+ void testUpdateForReverseDirectionFromRightToLeft() {
skeleton.patrollingLeft = false;
skeleton.setPosition(99);
skeleton.update();
- Assert.assertEquals(100, skeleton.getPosition());
- Assert.assertEquals(true, skeleton.patrollingLeft);
+ assertEquals(100, skeleton.getPosition());
+ assertTrue(skeleton.patrollingLeft);
}
}
diff --git a/update-method/src/test/java/com/iluwatar/updatemethod/StatueTest.java b/update-method/src/test/java/com/iluwatar/updatemethod/StatueTest.java
index 2d523237c..3b28ffd5d 100644
--- a/update-method/src/test/java/com/iluwatar/updatemethod/StatueTest.java
+++ b/update-method/src/test/java/com/iluwatar/updatemethod/StatueTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,36 +23,37 @@
package com.iluwatar.updatemethod;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
-public class StatueTest {
+import static org.junit.jupiter.api.Assertions.assertEquals;
- private Statue statue;
+class StatueTest {
- @Before
- public void setup() {
+ private static Statue statue;
+
+ @BeforeAll
+ public static void setup() {
statue = new Statue(1, 20);
}
- @After
- public void tearDown() {
+ @AfterAll
+ public static void tearDown() {
statue = null;
}
@Test
- public void testUpdateForPendingShoot() {
+ void testUpdateForPendingShoot() {
statue.frames = 10;
statue.update();
- Assert.assertEquals(11, statue.frames);
+ assertEquals(11, statue.frames);
}
@Test
- public void testUpdateForShooting() {
+ void testUpdateForShooting() {
statue.frames = 19;
statue.update();
- Assert.assertEquals(0, statue.frames);
+ assertEquals(0, statue.frames);
}
}
diff --git a/update-method/src/test/java/com/iluwatar/updatemethod/WorldTest.java b/update-method/src/test/java/com/iluwatar/updatemethod/WorldTest.java
index 2a9dad316..843c4a654 100644
--- a/update-method/src/test/java/com/iluwatar/updatemethod/WorldTest.java
+++ b/update-method/src/test/java/com/iluwatar/updatemethod/WorldTest.java
@@ -1,6 +1,6 @@
/*
* The MIT License
- * Copyright © 2014-2019 Ilkka Seppälä
+ * Copyright © 2014-2021 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
@@ -23,41 +23,44 @@
package com.iluwatar.updatemethod;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
-public class WorldTest {
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
- private World world;
+class WorldTest {
- @Before
- public void setup() {
+ private static World world;
+
+ @BeforeAll
+ public static void setup() {
world = new World();
}
- @After
- public void tearDown() {
+ @AfterAll
+ public static void tearDown() {
world = null;
}
@Test
- public void testRun() {
+ void testRun() {
world.run();
- Assert.assertEquals(true, world.isRunning);
+ assertTrue(world.isRunning);
}
@Test
- public void testStop() {
+ void testStop() {
world.stop();
- Assert.assertEquals(false, world.isRunning);
+ assertFalse(world.isRunning);
}
@Test
- public void testAddEntity() {
+ void testAddEntity() {
var entity = new Skeleton(1);
world.addEntity(entity);
- Assert.assertEquals(entity, world.entities.get(0));
+ assertEquals(entity, world.entities.get(0));
}
}
diff --git a/value-object/pom.xml b/value-object/pom.xml
index aa4101b5c..41c84af84 100644
--- a/value-object/pom.xml
+++ b/value-object/pom.xml
@@ -2,7 +2,7 @@