- + PotionFactory()
- ~ createPotion(type : PotionType) : Potion
- }
- enum PotionType {
- + HEALING {static}
- + HOLY_WATER {static}
- + INVISIBILITY {static}
- + POISON {static}
- + STRENGTH {static}
- + valueOf(name : String) : PotionType {static}
- + values() : PotionType[] {static}
- }
- class StrengthPotion {
- - LOGGER : Logger {static}
- + StrengthPotion()
- + drink()
- }
-}
-AlchemistShop --> "-topShelf" Potion
-HealingPotion ..|> Potion
-HolyWaterPotion ..|> Potion
-InvisibilityPotion ..|> Potion
-PoisonPotion ..|> Potion
-StrengthPotion ..|> Potion
-@enduml
\ No newline at end of file
diff --git a/flyweight/etc/flyweight_1.png b/flyweight/etc/flyweight_1.png
deleted file mode 100644
index f30225aa0..000000000
Binary files a/flyweight/etc/flyweight_1.png and /dev/null differ
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
index f5606e638..5952cf5f1 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
@@ -36,7 +36,7 @@ import org.slf4j.LoggerFactory;
*
* It is responsible for reading and loading the contents of a given file.
*/
-public class FileLoader implements Serializable{
+public class FileLoader implements Serializable {
/**
* Generated serial version UID
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
index 560a8d274..233b1dcf7 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
@@ -30,7 +30,7 @@ import java.io.Serializable;
*
* It is responsible for reacting to the user's actions and update the View component.
*/
-public class FileSelectorPresenter implements Serializable{
+public class FileSelectorPresenter implements Serializable {
/**
* Generated serial version UID
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java
index 5272ea0b7..e6ab93f66 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java
@@ -28,7 +28,7 @@ import java.io.Serializable;
* This interface represents the View component in the Model-View-Presenter pattern. It can be
* implemented by either the GUI components, or by the Stub.
*/
-public interface FileSelectorView extends Serializable{
+public interface FileSelectorView extends Serializable {
/**
* Opens the view.
diff --git a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
index f224a56f5..530db835d 100644
--- a/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
+++ b/mutex/src/test/java/com/iluwatar/mutex/AppTest.java
@@ -28,7 +28,7 @@ import java.io.IOException;
/**
* Application Test Entrypoint
*/
-public class AppTest{
+public class AppTest {
@Test
public void test() throws IOException {
String[] args = {};
diff --git a/naked-objects/README.md b/naked-objects/README.md
index 66e6ac2b0..eb1c083b1 100644
--- a/naked-objects/README.md
+++ b/naked-objects/README.md
@@ -29,4 +29,4 @@ Use the Naked Objects pattern when
## Credits
-* [Richard Pawson - Naked Objects](https://isis.apache.org/resources/thesis/Pawson-Naked-Objects-thesis.pdf)
+* [Richard Pawson - Naked Objects](http://downloads.nakedobjects.net/resources/Pawson%20thesis.pdf)
diff --git a/partial-response/README.md b/partial-response/README.md
new file mode 100644
index 000000000..5d03cb359
--- /dev/null
+++ b/partial-response/README.md
@@ -0,0 +1,29 @@
+---
+layout: pattern
+title: Partial Response
+folder: partial-response
+permalink: /patterns/partial-response/
+categories: Architectural
+tags:
+ - Java
+ - KISS
+ - YAGNI
+ - Difficulty-Beginner
+---
+
+## Intent
+Send partial response from server to client on need basis. Client will specify the the fields
+that it need to server, instead of serving all details for resource.
+
+
+
+## Applicability
+Use the Partial Response pattern when
+
+* Client need only subset of data from resource.
+* To avoid too much data transfer over wire
+
+## Credits
+
+* [Common Design Patterns](https://cloud.google.com/apis/design/design_patterns)
+* [Partial Response in RESTful API Design](http://yaoganglian.com/2013/07/01/partial-response/)
diff --git a/partial-response/etc/partial-response.ucls b/partial-response/etc/partial-response.ucls
new file mode 100644
index 000000000..a0b029496
--- /dev/null
+++ b/partial-response/etc/partial-response.ucls
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/partial-response/etc/partial-response.urm.png b/partial-response/etc/partial-response.urm.png
new file mode 100644
index 000000000..17dbd5f1b
Binary files /dev/null and b/partial-response/etc/partial-response.urm.png differ
diff --git a/partial-response/etc/partial-response.urm.puml b/partial-response/etc/partial-response.urm.puml
new file mode 100644
index 000000000..69efd0454
--- /dev/null
+++ b/partial-response/etc/partial-response.urm.puml
@@ -0,0 +1,31 @@
+@startuml
+package com.iluwatar.partialresponse {
+ class FieldJsonMapper {
+ + FieldJsonMapper()
+ - getString(video : Video, declaredField : Field) : String
+ + toJson(video : Video, fields : String[]) : String
+ }
+ class Video {
+ - description : String
+ - director : String
+ - id : Integer
+ - language : String
+ - length : Integer
+ - title : String
+ + Video(id : Integer, title : String, length : Integer, description : String, director : String, language : String)
+ + toString() : String
+ }
+ class VideoClientApp {
+ - LOGGER : Logger {static}
+ + VideoClientApp()
+ + main(args : String[]) {static}
+ }
+ class VideoResource {
+ - fieldJsonMapper : FieldJsonMapper
+ - videos : Map
+ + VideoResource(fieldJsonMapper : FieldJsonMapper, videos : Map)
+ + getDetails(id : Integer, fields : String[]) : String
+ }
+}
+VideoResource --> "-fieldJsonMapper" FieldJsonMapper
+@enduml
\ No newline at end of file
diff --git a/partial-response/pom.xml b/partial-response/pom.xml
new file mode 100644
index 000000000..ed685eb6a
--- /dev/null
+++ b/partial-response/pom.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.17.0-SNAPSHOT
+
+ 4.0.0
+
+ partial-response
+
+
+ junit
+ junit
+
+
+ org.mockito
+ mockito-core
+
+
+
+
+
\ No newline at end of file
diff --git a/partial-response/src/main/java/com/iluwatar/partialresponse/App.java b/partial-response/src/main/java/com/iluwatar/partialresponse/App.java
new file mode 100644
index 000000000..2977b50a7
--- /dev/null
+++ b/partial-response/src/main/java/com/iluwatar/partialresponse/App.java
@@ -0,0 +1,74 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2017 Gopinath Langote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.iluwatar.partialresponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The Partial response pattern is a design pattern in which client specifies fields to fetch to serve.
+ * Here {@link App} is playing as client for {@link VideoResource} server.
+ * Client ask for specific fields information in video to server.
+ *
+ *
+ * {@link VideoResource} act as server to serve video information.
+ */
+
+public class App {
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+
+ /**
+ * Method as act client and request to server for video details.
+ *
+ * @param args program argument.
+ */
+ public static void main(String[] args) throws Exception {
+ Map videos = new HashMap<>();
+ videos.put(1, new Video(1, "Avatar", 178, "epic science fiction film", "James Cameron", "English"));
+ videos.put(2, new Video(2, "Godzilla Resurgence", 120, "Action & drama movie|", "Hideaki Anno", "Japanese"));
+ videos.put(3, new Video(3, "Interstellar", 169, "Adventure & Sci-Fi", "Christopher Nolan", "English"));
+ VideoResource videoResource = new VideoResource(new FieldJsonMapper(), videos);
+
+
+ LOGGER.info("Retrieving full response from server:-");
+ LOGGER.info("Get all video information:");
+ String videoDetails = videoResource.getDetails(1);
+ LOGGER.info(videoDetails);
+
+ LOGGER.info("----------------------------------------------------------");
+
+ LOGGER.info("Retrieving partial response from server:-");
+ LOGGER.info("Get video @id, @title, @director:");
+ String specificFieldsDetails = videoResource.getDetails(3, "id", "title", "director");
+ LOGGER.info(specificFieldsDetails);
+
+ LOGGER.info("Get video @id, @length:");
+ String videoLength = videoResource.getDetails(3, "id", "length");
+ LOGGER.info(videoLength);
+ }
+}
diff --git a/partial-response/src/main/java/com/iluwatar/partialresponse/FieldJsonMapper.java b/partial-response/src/main/java/com/iluwatar/partialresponse/FieldJsonMapper.java
new file mode 100644
index 000000000..9283cfa69
--- /dev/null
+++ b/partial-response/src/main/java/com/iluwatar/partialresponse/FieldJsonMapper.java
@@ -0,0 +1,60 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2017 Gopinath Langote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.iluwatar.partialresponse;
+
+import java.lang.reflect.Field;
+
+/**
+ * Map a video to json
+ */
+public class FieldJsonMapper {
+
+ /**
+ * @param video object containing video information
+ * @param fields fields information to get
+ * @return json of required fields from video
+ */
+ public String toJson(Video video, String[] fields) throws Exception {
+ StringBuilder json = new StringBuilder().append("{");
+
+ for (int i = 0, fieldsLength = fields.length; i < fieldsLength; i++) {
+ json.append(getString(video, Video.class.getDeclaredField(fields[i])));
+ if (i != fieldsLength - 1) {
+ json.append(",");
+ }
+ }
+ json.append("}");
+ return json.toString();
+ }
+
+ private String getString(Video video, Field declaredField) throws IllegalAccessException {
+ declaredField.setAccessible(true);
+ Object value = declaredField.get(video);
+ if (declaredField.get(video) instanceof Integer) {
+ return "\"" + declaredField.getName() + "\"" + ": " + value;
+ }
+ return "\"" + declaredField.getName() + "\"" + ": " + "\"" + value.toString() + "\"";
+ }
+}
diff --git a/partial-response/src/main/java/com/iluwatar/partialresponse/Video.java b/partial-response/src/main/java/com/iluwatar/partialresponse/Video.java
new file mode 100644
index 000000000..e242965e3
--- /dev/null
+++ b/partial-response/src/main/java/com/iluwatar/partialresponse/Video.java
@@ -0,0 +1,70 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2017 Gopinath Langote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.iluwatar.partialresponse;
+
+/**
+ * {@link Video} is a entity to serve from server.It contains all video related information..
+ *
+ */
+public class Video {
+ private final Integer id;
+ private final String title;
+ private final Integer length;
+ private final String description;
+ private final String director;
+ private final String language;
+
+ /**
+ * @param id video unique id
+ * @param title video title
+ * @param length video length in minutes
+ * @param description video description by publisher
+ * @param director video director name
+ * @param language video language {private, public}
+ */
+ public Video(Integer id, String title, Integer length, String description, String director, String language) {
+ this.id = id;
+ this.title = title;
+ this.length = length;
+ this.description = description;
+ this.director = director;
+ this.language = language;
+ }
+
+ /**
+ * @return json representaion of video
+ */
+ @Override
+ public String toString() {
+ return "{"
+ + "\"id\": " + id + ","
+ + "\"title\": \"" + title + "\","
+ + "\"length\": " + length + ","
+ + "\"description\": \"" + description + "\","
+ + "\"director\": \"" + director + "\","
+ + "\"language\": \"" + language + "\","
+ + "}";
+ }
+}
diff --git a/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java b/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
new file mode 100644
index 000000000..2bf7a73c1
--- /dev/null
+++ b/partial-response/src/main/java/com/iluwatar/partialresponse/VideoResource.java
@@ -0,0 +1,57 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2017 Gopinath Langote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.iluwatar.partialresponse;
+
+import java.util.Map;
+
+/**
+ * The resource class which serves video information.
+ * This class act as server in the demo. Which has all video details.
+ */
+public class VideoResource {
+ private FieldJsonMapper fieldJsonMapper;
+ private Map videos;
+
+ /**
+ * @param fieldJsonMapper map object to json.
+ * @param videos initialize resource with existing videos. Act as database.
+ */
+ public VideoResource(FieldJsonMapper fieldJsonMapper, Map videos) {
+ this.fieldJsonMapper = fieldJsonMapper;
+ this.videos = videos;
+ }
+
+ /**
+ * @param id video id
+ * @param fields fields to get information about
+ * @return full response if no fields specified else partial response for given field.
+ */
+ public String getDetails(Integer id, String... fields) throws Exception {
+ if (fields.length == 0) {
+ return videos.get(id).toString();
+ }
+ return fieldJsonMapper.toJson(videos.get(id), fields);
+ }
+}
diff --git a/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java b/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java
new file mode 100644
index 000000000..2ac34dd0d
--- /dev/null
+++ b/partial-response/src/test/java/com/iluwatar/partialresponse/AppTest.java
@@ -0,0 +1,40 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2017 Gopinath Langote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.iluwatar.partialresponse;
+
+import org.junit.Test;
+
+/**
+ * Application test
+ */
+public class AppTest {
+
+ @Test
+ public void main() throws Exception {
+ String[] args = {};
+ App.main(args);
+ }
+
+}
\ No newline at end of file
diff --git a/partial-response/src/test/java/com/iluwatar/partialresponse/FieldJsonMapperTest.java b/partial-response/src/test/java/com/iluwatar/partialresponse/FieldJsonMapperTest.java
new file mode 100644
index 000000000..9bc078b57
--- /dev/null
+++ b/partial-response/src/test/java/com/iluwatar/partialresponse/FieldJsonMapperTest.java
@@ -0,0 +1,53 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2017 Gopinath Langote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.iluwatar.partialresponse;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * tests {@link FieldJsonMapper}.
+ */
+public class FieldJsonMapperTest {
+ private FieldJsonMapper mapper;
+
+ @Before
+ public void setUp() {
+ mapper = new FieldJsonMapper();
+ }
+
+ @Test
+ public void shouldReturnJsonForSpecifiedFieldsInVideo() throws Exception {
+ String[] fields = new String[]{"id", "title", "length"};
+ Video video = new Video(2, "Godzilla Resurgence", 120, "Action & drama movie|", "Hideaki Anno", "Japanese");
+
+ String jsonFieldResponse = mapper.toJson(video, fields);
+
+ String expectedDetails = "{\"id\": 2,\"title\": \"Godzilla Resurgence\",\"length\": 120}";
+ assertEquals(expectedDetails, jsonFieldResponse);
+ }
+}
\ No newline at end of file
diff --git a/partial-response/src/test/java/com/iluwatar/partialresponse/VideoResourceTest.java b/partial-response/src/test/java/com/iluwatar/partialresponse/VideoResourceTest.java
new file mode 100644
index 000000000..0453e8ffd
--- /dev/null
+++ b/partial-response/src/test/java/com/iluwatar/partialresponse/VideoResourceTest.java
@@ -0,0 +1,80 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2017 Gopinath Langote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.iluwatar.partialresponse;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * tests {@link VideoResource}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class VideoResourceTest {
+ @Mock
+ private FieldJsonMapper fieldJsonMapper;
+
+ private VideoResource resource;
+
+ @Before
+ public void setUp() {
+ Map videos = new HashMap<>();
+ videos.put(1, new Video(1, "Avatar", 178, "epic science fiction film", "James Cameron", "English"));
+ videos.put(2, new Video(2, "Godzilla Resurgence", 120, "Action & drama movie|", "Hideaki Anno", "Japanese"));
+ videos.put(3, new Video(3, "Interstellar", 169, "Adventure & Sci-Fi", "Christopher Nolan", "English"));
+ resource = new VideoResource(fieldJsonMapper, videos);
+ }
+
+ @Test
+ public void shouldGiveVideoDetailsById() throws Exception {
+ String actualDetails = resource.getDetails(1);
+
+ String expectedDetails = "{\"id\": 1,\"title\": \"Avatar\",\"length\": 178,\"description\": "
+ + "\"epic science fiction film\",\"director\": \"James Cameron\",\"language\": \"English\",}";
+ assertEquals(expectedDetails, actualDetails);
+ }
+
+ @Test
+ public void shouldGiveSpecifiedFieldsInformationOfVideo() throws Exception {
+ String[] fields = new String[]{"id", "title", "length"};
+
+ String expectedDetails = "{\"id\": 1,\"title\": \"Avatar\",\"length\": 178}";
+ when(fieldJsonMapper.toJson(any(Video.class), eq(fields))).thenReturn(expectedDetails);
+
+ String actualFieldsDetails = resource.getDetails(2, fields);
+
+ assertEquals(expectedDetails, actualFieldsDetails);
+ }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 44461b091..ed9981b34 100644
--- a/pom.xml
+++ b/pom.xml
@@ -145,6 +145,8 @@
cqrs
event-sourcing
data-transfer-object
+ throttling
+ partial-response
@@ -470,6 +472,10 @@
bridge
composite
decorator
+ facade
+ flyweight
+ proxy
+ chain
@@ -486,4 +492,4 @@
-
+
\ No newline at end of file
diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java
index df4d0cc79..dd40ec15b 100644
--- a/promise/src/main/java/com/iluwatar/promise/App.java
+++ b/promise/src/main/java/com/iluwatar/promise/App.java
@@ -65,7 +65,7 @@ public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
- private static final String DEFAULT_URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md";
+ private static final String DEFAULT_URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/promise/README.md";
private final ExecutorService executor;
private final CountDownLatch stopLatch;
diff --git a/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java
index 3629b4b5d..ae90a927e 100644
--- a/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java
+++ b/promise/src/main/java/com/iluwatar/promise/PromiseSupport.java
@@ -27,11 +27,16 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* A really simplified implementation of future that allows completing it successfully with a value
* or exceptionally with an exception.
*/
class PromiseSupport implements Future {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PromiseSupport.class);
private static final int RUNNING = 1;
private static final int FAILED = 2;
@@ -80,40 +85,34 @@ class PromiseSupport implements Future {
@Override
public T get() throws InterruptedException, ExecutionException {
- if (state == COMPLETED) {
- return value;
- } else if (state == FAILED) {
- throw new ExecutionException(exception);
- } else {
- synchronized (lock) {
+ synchronized (lock) {
+ while (state == RUNNING) {
lock.wait();
- if (state == COMPLETED) {
- return value;
- } else {
- throw new ExecutionException(exception);
- }
}
}
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
}
@Override
public T get(long timeout, TimeUnit unit)
- throws InterruptedException, ExecutionException, TimeoutException {
- if (state == COMPLETED) {
- return value;
- } else if (state == FAILED) {
- throw new ExecutionException(exception);
- } else {
- synchronized (lock) {
- lock.wait(unit.toMillis(timeout));
- if (state == COMPLETED) {
- return value;
- } else if (state == FAILED) {
- throw new ExecutionException(exception);
- } else {
- throw new TimeoutException();
+ throws ExecutionException, TimeoutException {
+ synchronized (lock) {
+ while (state == RUNNING) {
+ try {
+ lock.wait(unit.toMillis(timeout));
+ } catch (InterruptedException e) {
+ LOGGER.warn("Interrupted!", e);
+ Thread.currentThread().interrupt();
}
}
}
+
+ if (state == COMPLETED) {
+ return value;
+ }
+ throw new ExecutionException(exception);
}
}
\ No newline at end of file
diff --git a/proxy/README.md b/proxy/README.md
index 17f23de50..615c02ced 100644
--- a/proxy/README.md
+++ b/proxy/README.md
@@ -18,7 +18,97 @@ Surrogate
Provide a surrogate or placeholder for another object to control
access to it.
-
+## Explanation
+Real world example
+
+> Imagine a tower where the local wizards go to study their spells. The ivory tower can only be accessed through a proxy which ensures that only the first three wizards can enter. Here the proxy represents the functionality of the tower and adds access control to it.
+
+In plain words
+
+> Using the proxy pattern, a class represents the functionality of another class.
+
+Wikipedia says
+
+> A proxy, in its most general form, is a class functioning as an interface to something else. A proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked.
+
+**Programmatic Example**
+
+Taking our wizard tower example from above. Firstly we have the wizard tower interface and the ivory tower class
+
+```
+public interface WizardTower {
+
+ void enter(Wizard wizard);
+}
+
+public class IvoryTower implements WizardTower {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(IvoryTower.class);
+
+ public void enter(Wizard wizard) {
+ LOGGER.info("{} enters the tower.", wizard);
+ }
+
+}
+```
+
+Then a simple wizard class
+
+```
+public class Wizard {
+
+ private final String name;
+
+ public Wizard(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
+```
+
+Then we have the proxy to add access control to wizard tower
+
+```
+public class WizardTowerProxy implements WizardTower {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(WizardTowerProxy.class);
+
+ private static final int NUM_WIZARDS_ALLOWED = 3;
+
+ private int numWizards;
+
+ private final WizardTower tower;
+
+ public WizardTowerProxy(WizardTower tower) {
+ this.tower = tower;
+ }
+
+ @Override
+ public void enter(Wizard wizard) {
+ if (numWizards < NUM_WIZARDS_ALLOWED) {
+ tower.enter(wizard);
+ numWizards++;
+ } else {
+ LOGGER.info("{} is not allowed to enter!", wizard);
+ }
+ }
+}
+```
+
+And here is tower entering scenario
+
+```
+WizardTowerProxy proxy = new WizardTowerProxy(new IvoryTower());
+proxy.enter(new Wizard("Red wizard")); // Red wizard enters the tower.
+proxy.enter(new Wizard("White wizard")); // White wizard enters the tower.
+proxy.enter(new Wizard("Black wizard")); // Black wizard enters the tower.
+proxy.enter(new Wizard("Green wizard")); // Green wizard is not allowed to enter!
+proxy.enter(new Wizard("Brown wizard")); // Brown wizard is not allowed to enter!
+```
## Applicability
Proxy is applicable whenever there is a need for a more
diff --git a/proxy/etc/proxy.png b/proxy/etc/proxy.png
deleted file mode 100644
index 300e58dd3..000000000
Binary files a/proxy/etc/proxy.png and /dev/null differ
diff --git a/proxy/etc/proxy.ucls b/proxy/etc/proxy.ucls
deleted file mode 100644
index 76b5f0160..000000000
--- a/proxy/etc/proxy.ucls
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/proxy/etc/proxy.urm.puml b/proxy/etc/proxy.urm.puml
deleted file mode 100644
index ffe0fa446..000000000
--- a/proxy/etc/proxy.urm.puml
+++ /dev/null
@@ -1,32 +0,0 @@
-@startuml
-package com.iluwatar.proxy {
- class App {
- + App()
- + main(args : String[]) {static}
- }
- class IvoryTower {
- - LOGGER : Logger {static}
- + IvoryTower()
- + enter(wizard : Wizard)
- }
- class Wizard {
- - name : String
- + Wizard(name : String)
- + toString() : String
- }
- interface WizardTower {
- + enter(Wizard) {abstract}
- }
- class WizardTowerProxy {
- - LOGGER : Logger {static}
- - NUM_WIZARDS_ALLOWED : int {static}
- - numWizards : int
- - tower : WizardTower
- + WizardTowerProxy(tower : WizardTower)
- + enter(wizard : Wizard)
- }
-}
-WizardTowerProxy --> "-tower" WizardTower
-IvoryTower ..|> WizardTower
-WizardTowerProxy ..|> WizardTower
-@enduml
\ No newline at end of file
diff --git a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java b/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java
index 26d274262..5eaed3b2e 100644
--- a/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java
+++ b/semaphore/src/test/java/com/iluwatar/semaphore/AppTest.java
@@ -28,7 +28,7 @@ import java.io.IOException;
/**
* Application Test Entrypoint
*/
-public class AppTest{
+public class AppTest {
@Test
public void test() throws IOException {
String[] args = {};
diff --git a/throttling/README.md b/throttling/README.md
new file mode 100644
index 000000000..73d982bff
--- /dev/null
+++ b/throttling/README.md
@@ -0,0 +1,19 @@
+---
+layout: pattern
+title: Throttling
+folder: throttling
+permalink: /patterns/throttling/
+categories: Behavioral
+tags:
+ - Java
+ - Difficulty-Beginner
+---
+
+## Intent
+Ensure that a given client is not able to access service resources more than the assigned limit.
+
+## Applicability
+The Throttling pattern should be used:
+
+* when a service access needs to be restricted to not have high impacts on the performance of the service.
+* when multiple clients are consuming the same service resources and restriction has to be made according to the usage per client.
diff --git a/throttling/etc/throttling-pattern.png b/throttling/etc/throttling-pattern.png
new file mode 100644
index 000000000..a31aa54ce
Binary files /dev/null and b/throttling/etc/throttling-pattern.png differ
diff --git a/throttling/etc/throttling.urm.puml b/throttling/etc/throttling.urm.puml
new file mode 100644
index 000000000..8c97da50a
--- /dev/null
+++ b/throttling/etc/throttling.urm.puml
@@ -0,0 +1,29 @@
+@startuml
+package com.iluwatar.tls {
+ class App {
+ - LOGGER : Logger {static}
+ + App()
+ + main(args : String[]) {static}
+ - makeServiceCalls(service : B2BService) {static}
+ }
+ ~class B2BService {
+ - LOGGER : Logger {static}
+ - callsCounter : int
+ - tenant : Tenant
+ + B2BService(tenant : Tenant)
+ + dummyCustomerApi() : int
+ + getCurrentCallsCount() : int
+ - getRandomCustomerId() : int
+ }
+ class Tenant {
+ - allowedCallsPerSecond : int
+ - name : String
+ + Tenant(name : String, allowedCallsPerSecond : int)
+ + getAllowedCallsPerSecond() : int
+ + getName() : String
+ + setAllowedCallsPerSecond(allowedCallsPerSecond : int)
+ + setName(name : String)
+ }
+}
+B2BService --> "-tenant" Tenant
+@enduml
\ No newline at end of file
diff --git a/throttling/pom.xml b/throttling/pom.xml
new file mode 100644
index 000000000..2cbd7bf9e
--- /dev/null
+++ b/throttling/pom.xml
@@ -0,0 +1,44 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.17.0-SNAPSHOT
+
+ 4.0.0
+
+ throttling
+
+
+ junit
+ junit
+
+
+
+
\ No newline at end of file
diff --git a/throttling/src/main/java/com/iluwatar/throttling/App.java b/throttling/src/main/java/com/iluwatar/throttling/App.java
new file mode 100644
index 000000000..2dce68ab9
--- /dev/null
+++ b/throttling/src/main/java/com/iluwatar/throttling/App.java
@@ -0,0 +1,90 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014-2016 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.throttling;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.iluwatar.throttling.timer.Throttler;
+import com.iluwatar.throttling.timer.ThrottleTimerImpl;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Throttling pattern is a design pattern to throttle or limit the use of resources or even a complete service by
+ * users or a particular tenant. This can allow systems to continue to function and meet service level agreements,
+ * even when an increase in demand places load on resources.
+ *
+ * In this example we have ({@link App}) as the initiating point of the service.
+ * This is a time based throttling, i.e. only a certain number of calls are allowed per second.
+ *
+ * ({@link Tenant}) is the Tenant POJO class with which many tenants can be created
+ * ({@link B2BService}) is the service which is consumed by the tenants and is throttled.
+ */
+public class App {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+
+ /**
+ * Application entry point
+ * @param args main arguments
+ */
+ public static void main(String[] args) {
+
+ Tenant adidas = new Tenant("Adidas", 5);
+ Tenant nike = new Tenant("Nike", 6);
+
+ ExecutorService executorService = Executors.newFixedThreadPool(2);
+
+ executorService.execute(() -> makeServiceCalls(adidas));
+ executorService.execute(() -> makeServiceCalls(nike));
+
+ executorService.shutdown();
+ try {
+ executorService.awaitTermination(10, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ LOGGER.error("Executor Service terminated: {}", e.getMessage());
+ }
+ }
+
+ /**
+ * Make calls to the B2BService dummy API
+ * @param service an instance of B2BService
+ */
+ private static void makeServiceCalls(Tenant tenant) {
+ Throttler timer = new ThrottleTimerImpl(10);
+ B2BService service = new B2BService(timer);
+ for (int i = 0; i < 20; i++) {
+ service.dummyCustomerApi(tenant);
+// Sleep is introduced to keep the output in check and easy to view and analyze the results.
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ LOGGER.error("Thread interrupted: {}", e.getMessage());
+ }
+ }
+ }
+}
diff --git a/throttling/src/main/java/com/iluwatar/throttling/B2BService.java b/throttling/src/main/java/com/iluwatar/throttling/B2BService.java
new file mode 100644
index 000000000..c9acd4b73
--- /dev/null
+++ b/throttling/src/main/java/com/iluwatar/throttling/B2BService.java
@@ -0,0 +1,62 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.throttling;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.iluwatar.throttling.timer.Throttler;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * A service which accepts a tenant and throttles the resource based on the time given to the tenant.
+ */
+class B2BService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(B2BService.class);
+
+ public B2BService(Throttler timer) {
+ timer.start();
+ }
+
+ /**
+ *
+ * @return customer id which is randomly generated
+ */
+ public int dummyCustomerApi(Tenant tenant) {
+ String tenantName = tenant.getName();
+ int count = CallsCount.getCount(tenantName);
+ LOGGER.debug("Counter for {} : {} ", tenant.getName(), count);
+ if (count >= tenant.getAllowedCallsPerSecond()) {
+ LOGGER.error("API access per second limit reached for: {}", tenantName);
+ return -1;
+ }
+ CallsCount.incrementCount(tenantName);
+ return getRandomCustomerId();
+ }
+
+ private int getRandomCustomerId() {
+ return ThreadLocalRandom.current().nextInt(1, 10000);
+ }
+}
diff --git a/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java b/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java
new file mode 100644
index 000000000..81195b074
--- /dev/null
+++ b/throttling/src/main/java/com/iluwatar/throttling/CallsCount.java
@@ -0,0 +1,72 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.throttling;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A class to keep track of the counter of different Tenants
+ * @author drastogi
+ *
+ */
+public final class CallsCount {
+ private static Map tenantCallsCount = new ConcurrentHashMap<>();
+
+ /**
+ * Add a new tenant to the map.
+ * @param tenantName name of the tenant.
+ */
+ public static void addTenant(String tenantName) {
+ if (!tenantCallsCount.containsKey(tenantName)) {
+ tenantCallsCount.put(tenantName, 0);
+ }
+ }
+
+ /**
+ * Increment the count of the specified tenant.
+ * @param tenantName name of the tenant.
+ */
+ public static void incrementCount(String tenantName) {
+ tenantCallsCount.put(tenantName, tenantCallsCount.get(tenantName) + 1);
+ }
+
+ /**
+ *
+ * @param tenantName name of the tenant.
+ * @return the count of the tenant.
+ */
+ public static int getCount(String tenantName) {
+ return tenantCallsCount.get(tenantName);
+ }
+
+ /**
+ * Resets the count of all the tenants in the map.
+ */
+ public static void reset() {
+ for (Entry e : tenantCallsCount.entrySet()) {
+ tenantCallsCount.put(e.getKey(), 0);
+ }
+ }
+}
diff --git a/throttling/src/main/java/com/iluwatar/throttling/Tenant.java b/throttling/src/main/java/com/iluwatar/throttling/Tenant.java
new file mode 100644
index 000000000..a720e154b
--- /dev/null
+++ b/throttling/src/main/java/com/iluwatar/throttling/Tenant.java
@@ -0,0 +1,57 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.throttling;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A Pojo class to create a basic Tenant with the allowed calls per second.
+ */
+public class Tenant {
+
+ private String name;
+ private int allowedCallsPerSecond;
+
+ /**
+ *
+ * @param name Name of the tenant
+ * @param allowedCallsPerSecond The number of calls allowed for a particular tenant.
+ * @throws InvalidParameterException If number of calls is less than 0, throws exception.
+ */
+ public Tenant(String name, int allowedCallsPerSecond) {
+ if (allowedCallsPerSecond < 0) {
+ throw new InvalidParameterException("Number of calls less than 0 not allowed");
+ }
+ this.name = name;
+ this.allowedCallsPerSecond = allowedCallsPerSecond;
+ CallsCount.addTenant(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAllowedCallsPerSecond() {
+ return allowedCallsPerSecond;
+ }
+}
diff --git a/throttling/src/main/java/com/iluwatar/throttling/timer/ThrottleTimerImpl.java b/throttling/src/main/java/com/iluwatar/throttling/timer/ThrottleTimerImpl.java
new file mode 100644
index 000000000..4ff4ce246
--- /dev/null
+++ b/throttling/src/main/java/com/iluwatar/throttling/timer/ThrottleTimerImpl.java
@@ -0,0 +1,58 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/**
+ *
+ */
+package com.iluwatar.throttling.timer;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.iluwatar.throttling.CallsCount;
+
+/**
+ * Implementation of throttler interface. This class resets the counter every second.
+ * @author drastogi
+ *
+ */
+public class ThrottleTimerImpl implements Throttler {
+
+ private int throttlePeriod;
+
+ public ThrottleTimerImpl(int throttlePeriod) {
+ this.throttlePeriod = throttlePeriod;
+ }
+
+ /**
+ * A timer is initiated with this method. The timer runs every second and resets the
+ * counter.
+ */
+ public void start() {
+ new Timer(true).schedule(new TimerTask() {
+ @Override
+ public void run() {
+ CallsCount.reset();
+ }
+ }, 0, throttlePeriod);
+ }
+}
diff --git a/throttling/src/main/java/com/iluwatar/throttling/timer/Throttler.java b/throttling/src/main/java/com/iluwatar/throttling/timer/Throttler.java
new file mode 100644
index 000000000..24b73d92f
--- /dev/null
+++ b/throttling/src/main/java/com/iluwatar/throttling/timer/Throttler.java
@@ -0,0 +1,36 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/**
+ *
+ */
+package com.iluwatar.throttling.timer;
+
+/**
+ * An interface for defining the structure of different types of throttling ways.
+ * @author drastogi
+ *
+ */
+public interface Throttler {
+
+ void start();
+}
diff --git a/throttling/src/test/java/com/iluwatar/throttling/AppTest.java b/throttling/src/test/java/com/iluwatar/throttling/AppTest.java
new file mode 100644
index 000000000..37c8e75ec
--- /dev/null
+++ b/throttling/src/test/java/com/iluwatar/throttling/AppTest.java
@@ -0,0 +1,37 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.throttling;
+
+import org.junit.Test;
+
+/**
+ * Application test
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ final String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java b/throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java
new file mode 100644
index 000000000..b9ca1a1d8
--- /dev/null
+++ b/throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java
@@ -0,0 +1,49 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.throttling;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.iluwatar.throttling.timer.ThrottleTimerImpl;
+import com.iluwatar.throttling.timer.Throttler;
+
+/**
+ * B2BServiceTest class to test the B2BService
+ */
+public class B2BServiceTest {
+
+ @Test
+ public void dummyCustomerApiTest() {
+ Tenant tenant = new Tenant("testTenant", 2);
+ Throttler timer = new ThrottleTimerImpl(10);
+ B2BService service = new B2BService(timer);
+
+ for (int i = 0; i < 5; i++) {
+ service.dummyCustomerApi(tenant);
+ }
+
+ int counter = CallsCount.getCount(tenant.getName());
+ Assert.assertTrue("Counter limit must be reached", counter == 2);
+ }
+}
diff --git a/throttling/src/test/java/com/iluwatar/throttling/TenantTest.java b/throttling/src/test/java/com/iluwatar/throttling/TenantTest.java
new file mode 100644
index 000000000..2f0b5cf12
--- /dev/null
+++ b/throttling/src/test/java/com/iluwatar/throttling/TenantTest.java
@@ -0,0 +1,40 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.throttling;
+
+import org.junit.Test;
+
+import com.iluwatar.throttling.Tenant;
+
+import java.security.InvalidParameterException;
+
+/**
+ * TenantTest to test the creation of Tenant with valid parameters.
+ */
+public class TenantTest {
+
+ @Test(expected = InvalidParameterException.class)
+ public void constructorTest() {
+ Tenant tenant = new Tenant("FailTenant", -1);
+ }
+}