From 73925cef2ea6d99a8f75d4ad845925a03deba20e Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Sun, 3 Jun 2018 22:20:40 +0100 Subject: [PATCH 1/9] Ambassador adds logging, imitates trying to connect to remote service and provides new client-side functionality. Need to clean up code, add tests and add descriptive comments. --- ambassador/pom.xml | 15 ++++ .../java/com/iluwatar/ambassador/App.java | 19 +++++ .../java/com/iluwatar/ambassador/Client.java | 42 +++++++++ .../iluwatar/ambassador/RemoteService.java | 54 ++++++++++++ .../ambassador/RemoteServiceInterface.java | 28 ++++++ .../ambassador/ServiceAmbassador.java | 85 +++++++++++++++++++ pom.xml | 1 + 7 files changed, 244 insertions(+) create mode 100644 ambassador/pom.xml create mode 100644 ambassador/src/main/java/com/iluwatar/ambassador/App.java create mode 100644 ambassador/src/main/java/com/iluwatar/ambassador/Client.java create mode 100644 ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java create mode 100644 ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java create mode 100644 ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java diff --git a/ambassador/pom.xml b/ambassador/pom.xml new file mode 100644 index 000000000..b230a2736 --- /dev/null +++ b/ambassador/pom.xml @@ -0,0 +1,15 @@ + + + + java-design-patterns + com.iluwatar + 1.20.0-SNAPSHOT + + 4.0.0 + + ambassador + + + \ No newline at end of file diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/App.java b/ambassador/src/main/java/com/iluwatar/ambassador/App.java new file mode 100644 index 000000000..0293c1004 --- /dev/null +++ b/ambassador/src/main/java/com/iluwatar/ambassador/App.java @@ -0,0 +1,19 @@ +package com.iluwatar.ambassador; + +public class App { + + /** + * Entry point + */ + public static void main(String[] args) { + + Client host1 = new Client(); + Client host2 = new Client(); + + host1.useService(12); + host2.useService(73); + + host1.useNewService(12); + host2.useNewService(73); + } +} diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java new file mode 100644 index 000000000..0c7bb0394 --- /dev/null +++ b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java @@ -0,0 +1,42 @@ +/** + * 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.ambassador; + +public class Client { + + private ServiceAmbassador serviceAmbassador; + + Client() { + serviceAmbassador = new ServiceAmbassador(); + } + + void useService(int value) { + long result = serviceAmbassador.doRemoteFunction(value); + System.out.println(result); + } + + void useNewService(int value) { + long result = serviceAmbassador.doAddedFunction(value); + System.out.println(result); + } +} diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java new file mode 100644 index 000000000..0c608c151 --- /dev/null +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java @@ -0,0 +1,54 @@ +/** + * 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.ambassador; + +import static java.lang.Thread.sleep; + +public class RemoteService implements RemoteServiceInterface { + + private static RemoteService service = null; + + static synchronized RemoteService getRemoteService() { + if (service == null) { + service = new RemoteService(); + } + return service; + } + + private RemoteService() { + + } + + @Override + public long doRemoteFunction(int value) { + + long waitTime = (long) Math.floor(Math.random() * 1000); + + try { + sleep(waitTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return waitTime >= 200 ? value * 10 : -1; + } +} diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java new file mode 100644 index 000000000..50a097316 --- /dev/null +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java @@ -0,0 +1,28 @@ +/** + * 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.ambassador; + +interface RemoteServiceInterface { + + long doRemoteFunction(int value) throws Exception; +} diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java new file mode 100644 index 000000000..1c9a2325f --- /dev/null +++ b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java @@ -0,0 +1,85 @@ +/** + * 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.ambassador; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.lang.Thread.sleep; + +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; + + ServiceAmbassador() { + + } + + @Override + public long doRemoteFunction(int value) { + + return safeCall(value); + } + + long doAddedFunction(int value) { + return safeCall(value) * 5; + } + + private long checkLatency(int value) { + RemoteService service = RemoteService.getRemoteService(); + long startTime = System.currentTimeMillis(); + long result = service.doRemoteFunction(value); + long timeTaken = System.currentTimeMillis() - startTime; + + LOGGER.info("Time taken (ms): " + timeTaken); + return result; + } + + private long safeCall(int value) { + + int retries = 0; + long result = -1; + + for (int i = 0; i < RETRIES; i++) { + + if (retries >= RETRIES) { + return -1; + } + + if ((result = checkLatency(value)) == -1) { + LOGGER.info("Failed to reach remote: (" + (i + 1) + ")"); + retries++; + try { + sleep(DELAY_MS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + break; + } + } + return result; + } +} diff --git a/pom.xml b/pom.xml index e1d025c13..b44c6b843 100644 --- a/pom.xml +++ b/pom.xml @@ -161,6 +161,7 @@ dirty-flag trampoline serverless + ambassador From 6b10f4bdd1ca1ac97b03cb0ea5f2fc9eea0be00e Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Mon, 4 Jun 2018 20:36:10 +0100 Subject: [PATCH 2/9] Adding appropriate comments on classes and full description in App.java. Removing added function in ServiceAmbassador as it's not appropriate for the example. --- .../java/com/iluwatar/ambassador/App.java | 43 +++++++++++++++++-- .../java/com/iluwatar/ambassador/Client.java | 8 ++-- .../iluwatar/ambassador/RemoteService.java | 9 ++++ .../ambassador/RemoteServiceInterface.java | 3 ++ .../ambassador/ServiceAmbassador.java | 11 +++-- 5 files changed, 61 insertions(+), 13 deletions(-) diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/App.java b/ambassador/src/main/java/com/iluwatar/ambassador/App.java index 0293c1004..32c5f0f1c 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/App.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/App.java @@ -1,5 +1,44 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.ambassador; +/** + * + * The ambassador pattern creates a helper service that sends network requests on behalf of a + * client. It is often used in cloud-based applications to offload features of a remote service. + * + * An ambassador service can be thought of as an out-of-process proxy that is co-located with + * the client. Similar to the proxy design pattern, the ambassador service provides an interface + * for another remote service. In addition to the interface, the ambassador provides extra + * functionality and features, specifically offloaded common connectivity tasks. This usually + * consists of monitoring, logging, routing, security etc. This is extremely useful in + * legacy applications where the codebase is difficult to modify and allows for improvements + * in the application's networking capabilities. + * + * In this example, we will the ({@link ServiceAmbassador}) class represents the ambassador while the + * ({@link RemoteService}) class represents a remote application. + * + */ public class App { /** @@ -9,11 +48,7 @@ public class App { Client host1 = new Client(); Client host2 = new Client(); - host1.useService(12); host2.useService(73); - - host1.useNewService(12); - host2.useNewService(73); } } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java index 0c7bb0394..30bd834e6 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java @@ -22,6 +22,9 @@ */ package com.iluwatar.ambassador; +/** + * A simple Client + */ public class Client { private ServiceAmbassador serviceAmbassador; @@ -34,9 +37,4 @@ public class Client { long result = serviceAmbassador.doRemoteFunction(value); System.out.println(result); } - - void useNewService(int value) { - long result = serviceAmbassador.doAddedFunction(value); - System.out.println(result); - } } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java index 0c608c151..668e776ce 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java @@ -24,6 +24,9 @@ package com.iluwatar.ambassador; import static java.lang.Thread.sleep; +/** + * A remote legacy application represented by a Singleton implementation. + */ public class RemoteService implements RemoteServiceInterface { private static RemoteService service = null; @@ -39,6 +42,12 @@ public class RemoteService implements RemoteServiceInterface { } + /** + * Remote function takes a value and multiplies it by 10 taking a random amount of time. + * Will sometimes return -1. This immitates connectivity issues a client might have to account for. + * @param value integer value to be multiplied. + * @return if waitTime is more than 200ms, it returns value * 10, otherwise -1. + */ @Override public long doRemoteFunction(int value) { diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java index 50a097316..9f1112da9 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java @@ -22,6 +22,9 @@ */ package com.iluwatar.ambassador; +/** + * Interface shared by ({@link RemoteService}) and ({@link ServiceAmbassador}). + */ interface RemoteServiceInterface { long doRemoteFunction(int value) throws Exception; diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java index 1c9a2325f..77c7197ff 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java @@ -27,6 +27,13 @@ import org.slf4j.LoggerFactory; import static java.lang.Thread.sleep; +/** + * + * 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. + * + */ public class ServiceAmbassador implements RemoteServiceInterface { private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAmbassador.class); @@ -43,10 +50,6 @@ public class ServiceAmbassador implements RemoteServiceInterface { return safeCall(value); } - long doAddedFunction(int value) { - return safeCall(value) * 5; - } - private long checkLatency(int value) { RemoteService service = RemoteService.getRemoteService(); long startTime = System.currentTimeMillis(); From 74190e36bb049182ac92889551b5eeedb0dde377 Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Mon, 4 Jun 2018 21:20:04 +0100 Subject: [PATCH 3/9] Adding tests for each class. --- ambassador/pom.xml | 16 +++++++++ .../java/com/iluwatar/ambassador/Client.java | 3 +- .../java/com/iluwatar/ambassador/AppTest.java | 36 +++++++++++++++++++ .../com/iluwatar/ambassador/ClientTest.java | 15 ++++++++ .../ambassador/RemoteServiceTest.java | 16 +++++++++ .../ambassador/ServiceAmbassadorTest.java | 13 +++++++ 6 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java create mode 100644 ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java create mode 100644 ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java create mode 100644 ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java diff --git a/ambassador/pom.xml b/ambassador/pom.xml index b230a2736..fc3dbf37c 100644 --- a/ambassador/pom.xml +++ b/ambassador/pom.xml @@ -10,6 +10,22 @@ 4.0.0 ambassador + + + org.testng + testng + RELEASE + test + + + junit + junit + + + org.junit.jupiter + junit-jupiter-api + + \ No newline at end of file diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java index 30bd834e6..39c0e7273 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java @@ -33,8 +33,9 @@ public class Client { serviceAmbassador = new ServiceAmbassador(); } - void useService(int value) { + long useService(int value) { long result = serviceAmbassador.doRemoteFunction(value); System.out.println(result); + return result; } } diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java new file mode 100644 index 000000000..686a18af3 --- /dev/null +++ b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ambassador; + +import org.junit.jupiter.api.Test; + +/** + * Application test + */ +public class AppTest { + + @Test + public void test() { + 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 new file mode 100644 index 000000000..e02321fea --- /dev/null +++ b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java @@ -0,0 +1,15 @@ +package com.iluwatar.ambassador; + +import org.junit.jupiter.api.Test; + +public class ClientTest { + + @Test + public void test() { + + Client client = new Client(); + long result = client.useService(10); + assert result == 100 || result == -1; + + } +} diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java new file mode 100644 index 000000000..0e7b6a58d --- /dev/null +++ b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java @@ -0,0 +1,16 @@ +package com.iluwatar.ambassador; + +import org.junit.jupiter.api.Test; + +public class RemoteServiceTest { + + @Test + public void test() { + + RemoteService remoteService = RemoteService.getRemoteService(); + long result = remoteService.doRemoteFunction(10); + + assert result == 100 || result == -1; + } + +} diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java new file mode 100644 index 000000000..9bd87d3f8 --- /dev/null +++ b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java @@ -0,0 +1,13 @@ +package com.iluwatar.ambassador; + +import org.junit.jupiter.api.Test; + +public class ServiceAmbassadorTest { + + @Test + public void test() { + ServiceAmbassador ambassador = new ServiceAmbassador(); + long result = ambassador.doRemoteFunction(10); + assert result == 100 || result == -1; + } +} From bae51f5803df47a857d7084a866c8adb1f314cda Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Mon, 4 Jun 2018 21:27:04 +0100 Subject: [PATCH 4/9] Adding license to test classes. --- .../com/iluwatar/ambassador/ClientTest.java | 22 +++++++++++++++++++ .../ambassador/RemoteServiceTest.java | 22 +++++++++++++++++++ .../ambassador/ServiceAmbassadorTest.java | 22 +++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java index e02321fea..efdb5f133 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.ambassador; import org.junit.jupiter.api.Test; diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java index 0e7b6a58d..e8dfc62c2 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.ambassador; import org.junit.jupiter.api.Test; diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java index 9bd87d3f8..613592dd4 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.ambassador; import org.junit.jupiter.api.Test; From 5393c96247bc5e8b3a29116add497ed0e4fdb049 Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Mon, 4 Jun 2018 22:32:05 +0100 Subject: [PATCH 5/9] Adding README.md --- ambassador/README.md | 181 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 ambassador/README.md diff --git a/ambassador/README.md b/ambassador/README.md new file mode 100644 index 000000000..44d0a8de8 --- /dev/null +++ b/ambassador/README.md @@ -0,0 +1,181 @@ +--- +layout: pattern +title: Ambassador +folder: ambassador +permalink: /patterns/ambassador/ +categories: Structural +tags: + - Java + - Difficulty-Intermediate +--- + +## Intent +Provide a helper service that sends network requests on behalf of a client and offload common additional connectivity tasks. + +## Explanation +Real world example + +> A remote service has many clients accessing a function it provides. The service is a legacy application and is impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request frequency should be implemented along with latency checks and client-side logging. + +In plain words + +> Using the ambassador pattern, we can implement less-frequent polling from clients along with latency checks and logging. + +Microsoft documentation states + +> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client. + This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features. + +**Programmatic Example** + +With the above example in mind we will imitate the functionality in a simple manner. We have an interface implemented by the remote service as well as the ambassador service: + +```java +interface RemoteServiceInterface { + + long doRemoteFunction(int value) throws Exception; +} +``` + +A remote services represented as a singleton. + +```java +public class RemoteService implements RemoteServiceInterface { + + private static RemoteService service = null; + + static synchronized RemoteService getRemoteService() { + if (service == null) { + service = new RemoteService(); + } + return service; + } + + private RemoteService() { + + } + + @Override + public long doRemoteFunction(int value) { + + long waitTime = (long) Math.floor(Math.random() * 1000); + + try { + sleep(waitTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return waitTime >= 200 ? value * 10 : -1; + } +} +``` + +A service ambassador adding additional features such as logging, latency checks + +```java +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; + + ServiceAmbassador() { + + } + + @Override + public long doRemoteFunction(int value) { + + return safeCall(value); + } + + private long checkLatency(int value) { + RemoteService service = RemoteService.getRemoteService(); + long startTime = System.currentTimeMillis(); + long result = service.doRemoteFunction(value); + long timeTaken = System.currentTimeMillis() - startTime; + + LOGGER.info("Time taken (ms): " + timeTaken); + return result; + } + + private long safeCall(int value) { + + int retries = 0; + long result = -1; + + for (int i = 0; i < RETRIES; i++) { + + if (retries >= RETRIES) { + return -1; + } + + if ((result = checkLatency(value)) == -1) { + LOGGER.info("Failed to reach remote: (" + (i + 1) + ")"); + retries++; + try { + sleep(DELAY_MS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + break; + } + } + return result; + } +} +``` + +A client has a local service ambassador used to interact with the remote service: + +```java +public class Client { + + private ServiceAmbassador serviceAmbassador; + + Client() { + serviceAmbassador = new ServiceAmbassador(); + } + + long useService(int value) { + long result = serviceAmbassador.doRemoteFunction(value); + System.out.println(result); + return result; + } +} +``` + +And here are two clients using the service. + +```java +Client host1 = new Client(); +Client host2 = new Client(); +host1.useService(12); +host2.useService(73); +``` + +## Applicability +Ambassador is applicable when working with a legacy remote service that cannot +be modified or would be extremely difficult to modify. Connectivity features can +be implemented on the client avoiding the need for changes on the remote service. + +* Ambassador provides a local interface for a remote service. +* Ambassador provides logging, circuit breaking, retries and security on the client. + +## Typical Use Case + +* Control access to another object +* Implement logging +* Implement circuit breaking +* Offload remote service tasks +* Facilitate network connection + +## Real world examples + +* [Kubernetes-native API gateway for microservices](https://github.com/datawire/ambassador) + +## Credits + +* [Ambassador pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador) +* [Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services](https://books.google.co.uk/books?id=6BJNDwAAQBAJ&pg=PT35&lpg=PT35&dq=ambassador+pattern+in+real+world&source=bl&ots=d2e7GhYdHi&sig=Lfl_MDnCgn6lUcjzOg4GXrN13bQ&hl=en&sa=X&ved=0ahUKEwjk9L_18rrbAhVpKcAKHX_KA7EQ6AEIWTAI#v=onepage&q=ambassador%20pattern%20in%20real%20world&f=false) From ff579fabcf500d92c048c19f2fc4b4e7177b7280 Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Mon, 4 Jun 2018 22:50:59 +0100 Subject: [PATCH 6/9] Fixing CheckStyle issues. --- .../java/com/iluwatar/ambassador/App.java | 19 +++-- .../java/com/iluwatar/ambassador/Client.java | 18 ++--- .../iluwatar/ambassador/RemoteService.java | 52 +++++++------- .../ambassador/RemoteServiceInterface.java | 4 +- .../ambassador/ServiceAmbassador.java | 72 +++++++++---------- 5 files changed, 82 insertions(+), 83 deletions(-) diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/App.java b/ambassador/src/main/java/com/iluwatar/ambassador/App.java index 32c5f0f1c..e4b4d392a 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/App.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/App.java @@ -41,14 +41,13 @@ package com.iluwatar.ambassador; */ public class App { - /** - * Entry point - */ - public static void main(String[] args) { - - Client host1 = new Client(); - Client host2 = new Client(); - host1.useService(12); - host2.useService(73); - } + /** + * Entry point + */ + public static void main(String[] args) { + Client host1 = new Client(); + Client host2 = new Client(); + host1.useService(12); + host2.useService(73); + } } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java index 39c0e7273..eb02b9ee3 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java @@ -27,15 +27,15 @@ package com.iluwatar.ambassador; */ public class Client { - private ServiceAmbassador serviceAmbassador; + private ServiceAmbassador serviceAmbassador; - Client() { - serviceAmbassador = new ServiceAmbassador(); - } + Client() { + serviceAmbassador = new ServiceAmbassador(); + } - long useService(int value) { - long result = serviceAmbassador.doRemoteFunction(value); - System.out.println(result); - return result; - } + long useService(int value) { + long result = serviceAmbassador.doRemoteFunction(value); + System.out.println(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 668e776ce..cd34ae398 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java @@ -29,35 +29,35 @@ import static java.lang.Thread.sleep; */ public class RemoteService implements RemoteServiceInterface { - private static RemoteService service = null; + private static RemoteService service = null; - static synchronized RemoteService getRemoteService() { - if (service == null) { - service = new RemoteService(); - } - return service; + static synchronized RemoteService getRemoteService() { + if (service == null) { + service = new RemoteService(); } + return service; + } - private RemoteService() { + private RemoteService() { + } + + /** + * Remote function takes a value and multiplies it by 10 taking a random amount of time. + * Will sometimes return -1. This immitates connectivity issues a client might have to account for. + * @param value integer value to be multiplied. + * @return if waitTime is more than 200ms, it returns value * 10, otherwise -1. + */ + @Override + public long doRemoteFunction(int value) { + + long waitTime = (long) Math.floor(Math.random() * 1000); + + try { + sleep(waitTime); + } catch (InterruptedException e) { + e.printStackTrace(); } - - /** - * Remote function takes a value and multiplies it by 10 taking a random amount of time. - * Will sometimes return -1. This immitates connectivity issues a client might have to account for. - * @param value integer value to be multiplied. - * @return if waitTime is more than 200ms, it returns value * 10, otherwise -1. - */ - @Override - public long doRemoteFunction(int value) { - - long waitTime = (long) Math.floor(Math.random() * 1000); - - try { - sleep(waitTime); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return waitTime >= 200 ? value * 10 : -1; - } + return waitTime >= 200 ? value * 10 : -1; + } } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java index 9f1112da9..940313de3 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteServiceInterface.java @@ -26,6 +26,6 @@ package com.iluwatar.ambassador; * Interface shared by ({@link RemoteService}) and ({@link ServiceAmbassador}). */ interface RemoteServiceInterface { - - long doRemoteFunction(int value) throws Exception; + + long doRemoteFunction(int value) throws Exception; } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java index 77c7197ff..54426f6cc 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java @@ -36,53 +36,53 @@ import static java.lang.Thread.sleep; */ 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; + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAmbassador.class); + private static final int RETRIES = 3; + private static final int DELAY_MS = 3000; - ServiceAmbassador() { + ServiceAmbassador() { - } + } - @Override - public long doRemoteFunction(int value) { + @Override + public long doRemoteFunction(int value) { - return safeCall(value); - } + return safeCall(value); + } - private long checkLatency(int value) { - RemoteService service = RemoteService.getRemoteService(); - long startTime = System.currentTimeMillis(); - long result = service.doRemoteFunction(value); - long timeTaken = System.currentTimeMillis() - startTime; + private long checkLatency(int value) { + RemoteService service = RemoteService.getRemoteService(); + long startTime = System.currentTimeMillis(); + long result = service.doRemoteFunction(value); + long timeTaken = System.currentTimeMillis() - startTime; - LOGGER.info("Time taken (ms): " + timeTaken); - return result; - } + LOGGER.info("Time taken (ms): " + timeTaken); + return result; + } - private long safeCall(int value) { + private long safeCall(int value) { - int retries = 0; - long result = -1; + int retries = 0; + long result = -1; - for (int i = 0; i < RETRIES; i++) { + for (int i = 0; i < RETRIES; i++) { - if (retries >= RETRIES) { - return -1; - } + if (retries >= RETRIES) { + return -1; + } - if ((result = checkLatency(value)) == -1) { - LOGGER.info("Failed to reach remote: (" + (i + 1) + ")"); - retries++; - try { - sleep(DELAY_MS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } else { - break; - } + if ((result = checkLatency(value)) == -1) { + LOGGER.info("Failed to reach remote: (" + (i + 1) + ")"); + retries++; + try { + sleep(DELAY_MS); + } catch (InterruptedException e) { + e.printStackTrace(); } - return result; + } else { + break; + } } + return result; + } } From c4dd94a019d937973b4832f679a4a0711cae2a0e Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Tue, 5 Jun 2018 07:32:29 +0100 Subject: [PATCH 7/9] Fixing CheckStyle issues in Test classes. --- .../java/com/iluwatar/ambassador/AppTest.java | 8 ++++---- .../java/com/iluwatar/ambassador/ClientTest.java | 15 +++++++++------ .../iluwatar/ambassador/RemoteServiceTest.java | 16 +++++++++------- .../ambassador/ServiceAmbassadorTest.java | 15 +++++++++------ 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java index 686a18af3..cb072c1eb 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/AppTest.java @@ -29,8 +29,8 @@ import org.junit.jupiter.api.Test; */ public class AppTest { - @Test - public void test() { - App.main(new String[]{}); - } + @Test + public void test() { + 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 efdb5f133..9354c4f86 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/ClientTest.java @@ -24,14 +24,17 @@ package com.iluwatar.ambassador; import org.junit.jupiter.api.Test; +/** + * Test for {@link Client} + */ public class ClientTest { - @Test - public void test() { + @Test + public void test() { - Client client = new Client(); - long result = client.useService(10); - assert result == 100 || result == -1; + Client client = new Client(); + long result = client.useService(10); - } + assert result == 100 || result == -1; + } } diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java index e8dfc62c2..e2e0e9be9 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java @@ -24,15 +24,17 @@ package com.iluwatar.ambassador; import org.junit.jupiter.api.Test; +/** + * Test for {@link RemoteService} + */ public class RemoteServiceTest { - @Test - public void test() { + @Test + public void test() { - RemoteService remoteService = RemoteService.getRemoteService(); - long result = remoteService.doRemoteFunction(10); - - assert result == 100 || result == -1; - } + RemoteService remoteService = RemoteService.getRemoteService(); + long result = remoteService.doRemoteFunction(10); + assert result == 100 || result == -1; + } } diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java index 613592dd4..ba701d426 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java @@ -24,12 +24,15 @@ package com.iluwatar.ambassador; import org.junit.jupiter.api.Test; +/** + * Test for {@link ServiceAmbassador} + */ public class ServiceAmbassadorTest { - @Test - public void test() { - ServiceAmbassador ambassador = new ServiceAmbassador(); - long result = ambassador.doRemoteFunction(10); - assert result == 100 || result == -1; - } + @Test + public void test() { + ServiceAmbassador ambassador = new ServiceAmbassador(); + long result = ambassador.doRemoteFunction(10); + assert result == 100 || result == -1; + } } From 868e4561b5749a33842e4988bdbf869f25d4df0e Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Tue, 5 Jun 2018 21:16:16 +0100 Subject: [PATCH 8/9] Updating pom dependencies and adding license. --- ambassador/pom.xml | 69 +++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/ambassador/pom.xml b/ambassador/pom.xml index fc3dbf37c..f47b76f9a 100644 --- a/ambassador/pom.xml +++ b/ambassador/pom.xml @@ -1,31 +1,48 @@ + - - java-design-patterns - com.iluwatar - 1.20.0-SNAPSHOT - - 4.0.0 - - ambassador - - - org.testng - testng - RELEASE - test - - - junit - junit - - - org.junit.jupiter - junit-jupiter-api - - - - + + java-design-patterns + com.iluwatar + 1.20.0-SNAPSHOT + + 4.0.0 + ambassador + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + \ No newline at end of file From 0453bf9063a8518ce1dd56dcde4eeed106dd4954 Mon Sep 17 00:00:00 2001 From: Ovidijus Okinskas Date: Sat, 23 Jun 2018 13:24:07 +0100 Subject: [PATCH 9/9] General cleanup. Simplifying code. Replacing all prints with appropriate Logger. --- ambassador/README.md | 19 ++++++++----------- .../java/com/iluwatar/ambassador/Client.java | 13 +++++++------ .../iluwatar/ambassador/RemoteService.java | 12 +++++++----- .../ambassador/ServiceAmbassador.java | 10 +++------- .../ambassador/RemoteServiceTest.java | 5 +---- .../ambassador/ServiceAmbassadorTest.java | 3 +-- 6 files changed, 27 insertions(+), 35 deletions(-) diff --git a/ambassador/README.md b/ambassador/README.md index 44d0a8de8..f23d1e13c 100644 --- a/ambassador/README.md +++ b/ambassador/README.md @@ -10,7 +10,7 @@ tags: --- ## Intent -Provide a helper service that sends network requests on behalf of a client and offload common additional connectivity tasks. +Provide a helper service instance on a client and offload common functionality away from a shared resource. ## Explanation Real world example @@ -42,7 +42,8 @@ A remote services represented as a singleton. ```java public class RemoteService implements RemoteServiceInterface { - private static RemoteService service = null; + private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class); + private static RemoteService service = null;2 static synchronized RemoteService getRemoteService() { if (service == null) { @@ -51,9 +52,7 @@ public class RemoteService implements RemoteServiceInterface { return service; } - private RemoteService() { - - } + private RemoteService() {} @Override public long doRemoteFunction(int value) { @@ -63,7 +62,7 @@ public class RemoteService implements RemoteServiceInterface { try { sleep(waitTime); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("Thread sleep interrupted", e) } return waitTime >= 200 ? value * 10 : -1; } @@ -79,9 +78,7 @@ public class ServiceAmbassador implements RemoteServiceInterface { private static final int RETRIES = 3; private static final int DELAY_MS = 3000; - ServiceAmbassador() { - - } + ServiceAmbassador() {} @Override public long doRemoteFunction(int value) { @@ -116,7 +113,7 @@ public class ServiceAmbassador implements RemoteServiceInterface { try { sleep(DELAY_MS); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("Thread sleep state interrupted", e); } } else { break; @@ -140,7 +137,7 @@ public class Client { long useService(int value) { long result = serviceAmbassador.doRemoteFunction(value); - System.out.println(result); + LOGGER.info("Service result: " + result) return result; } } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java index eb02b9ee3..983226530 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/Client.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/Client.java @@ -22,20 +22,21 @@ */ package com.iluwatar.ambassador; +import org.slf4j.LoggerFactory; + +import org.slf4j.Logger; + /** * A simple Client */ public class Client { - private ServiceAmbassador serviceAmbassador; - - Client() { - serviceAmbassador = new ServiceAmbassador(); - } + private static final Logger LOGGER = LoggerFactory.getLogger(Client.class); + private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador(); long useService(int value) { long result = serviceAmbassador.doRemoteFunction(value); - System.out.println(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 cd34ae398..225e033d8 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/RemoteService.java @@ -22,6 +22,9 @@ */ package com.iluwatar.ambassador; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import static java.lang.Thread.sleep; /** @@ -29,6 +32,7 @@ import static java.lang.Thread.sleep; */ public class RemoteService implements RemoteServiceInterface { + private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class); private static RemoteService service = null; static synchronized RemoteService getRemoteService() { @@ -38,13 +42,11 @@ public class RemoteService implements RemoteServiceInterface { return service; } - private RemoteService() { - - } + private RemoteService() {} /** * Remote function takes a value and multiplies it by 10 taking a random amount of time. - * Will sometimes return -1. This immitates connectivity issues a client might have to account for. + * Will sometimes return -1. This imitates connectivity issues a client might have to account for. * @param value integer value to be multiplied. * @return if waitTime is more than 200ms, it returns value * 10, otherwise -1. */ @@ -56,7 +58,7 @@ public class RemoteService implements RemoteServiceInterface { try { sleep(waitTime); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("Thread sleep state interrupted", e); } return waitTime >= 200 ? value * 10 : -1; } diff --git a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java index 54426f6cc..4be1dfcbf 100644 --- a/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java +++ b/ambassador/src/main/java/com/iluwatar/ambassador/ServiceAmbassador.java @@ -40,20 +40,16 @@ public class ServiceAmbassador implements RemoteServiceInterface { private static final int RETRIES = 3; private static final int DELAY_MS = 3000; - ServiceAmbassador() { - - } + ServiceAmbassador() {} @Override public long doRemoteFunction(int value) { - return safeCall(value); } private long checkLatency(int value) { - RemoteService service = RemoteService.getRemoteService(); long startTime = System.currentTimeMillis(); - long result = service.doRemoteFunction(value); + long result = RemoteService.getRemoteService().doRemoteFunction(value); long timeTaken = System.currentTimeMillis() - startTime; LOGGER.info("Time taken (ms): " + timeTaken); @@ -77,7 +73,7 @@ public class ServiceAmbassador implements RemoteServiceInterface { try { sleep(DELAY_MS); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error("Thread sleep state interrupted", e); } } else { break; diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java index e2e0e9be9..e0b297af4 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/RemoteServiceTest.java @@ -31,10 +31,7 @@ public class RemoteServiceTest { @Test public void test() { - - RemoteService remoteService = RemoteService.getRemoteService(); - long result = remoteService.doRemoteFunction(10); - + long result = RemoteService.getRemoteService().doRemoteFunction(10); assert result == 100 || result == -1; } } diff --git a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java index ba701d426..432df9fd1 100644 --- a/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java +++ b/ambassador/src/test/java/com/iluwatar/ambassador/ServiceAmbassadorTest.java @@ -31,8 +31,7 @@ public class ServiceAmbassadorTest { @Test public void test() { - ServiceAmbassador ambassador = new ServiceAmbassador(); - long result = ambassador.doRemoteFunction(10); + long result = new ServiceAmbassador().doRemoteFunction(10); assert result == 100 || result == -1; } }