From d80edd1ed3c913b5d9003884b20928329fcced44 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:08:12 +0100 Subject: [PATCH 01/40] Create test --- tls/test | 1 + 1 file changed, 1 insertion(+) create mode 100644 tls/test diff --git a/tls/test b/tls/test new file mode 100644 index 000000000..e8689b24f --- /dev/null +++ b/tls/test @@ -0,0 +1 @@ +hh From 7067d1ae568daa0f2acf60b1b8add09f3a87d1e6 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:24:03 +0100 Subject: [PATCH 02/40] Create test --- tls/src/main/java/com/iluwatar/tls/test | 1 + 1 file changed, 1 insertion(+) create mode 100644 tls/src/main/java/com/iluwatar/tls/test diff --git a/tls/src/main/java/com/iluwatar/tls/test b/tls/src/main/java/com/iluwatar/tls/test new file mode 100644 index 000000000..1df28a22d --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/test @@ -0,0 +1 @@ +ss From c4eb198a8d7c2fbb492342e7724bb336dcb789eb Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:27:28 +0100 Subject: [PATCH 03/40] Upload code files --- tls/src/main/java/com/iluwatar/tls/App.java | 108 +++++++++++++++++ .../main/java/com/iluwatar/tls/AppUgly.java | 112 ++++++++++++++++++ .../com/iluwatar/tls/DateFormatRunnable.java | 84 +++++++++++++ .../iluwatar/tls/DateFormatUglyRunnable.java | 76 ++++++++++++ 4 files changed, 380 insertions(+) create mode 100644 tls/src/main/java/com/iluwatar/tls/App.java create mode 100644 tls/src/main/java/com/iluwatar/tls/AppUgly.java create mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java create mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java new file mode 100644 index 000000000..b16aa1fc6 --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/App.java @@ -0,0 +1,108 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + * ThreadLocal pattern + *

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

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

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

+ * SimpleDateFormat is one of the basic Java classes and is not thread-safe. If + * you do not isolate the instance of SimpleDateFormat per each thread then + * problems arise. These problems are described with the example {@link AppUgly} + * + */ +public class App { + // A list to collect the date values created in the the threads + static List dateList = Collections.synchronizedList(new ArrayList()); + + // A list to collect Exceptions thrown in the threads (should be none in + // this example) + static List exceptionList = Collections.synchronizedList(new ArrayList()); + + /** + * Program entry point + * + * @param args + * command line args + */ + public static void main(String[] args) { + int counterDateValues = 0; + int counterExceptions = 0; + + // Create a runnable + DateFormatRunnable runnableDf = new DateFormatRunnable("dd/MM/yyyy", "15/12/2015"); + // start 4 threads, each using the same Runnable instance + Thread t1 = new Thread(runnableDf); + Thread t2 = new Thread(runnableDf); + Thread t3 = new Thread(runnableDf); + Thread t4 = new Thread(runnableDf); + t1.start(); + t2.start(); + t3.start(); + t4.start(); + try { + t1.join(); + t2.join(); + t3.join(); + t4.join(); + } catch (InterruptedException e) { + // Action not coded here + } + for (Date dt : dateList) { + // a correct run should deliver 20 times 15.12.2015 + counterDateValues++; + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + // Formatted output of the date value: DD.MM.YYYY + System.out.println( + cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); + } + for (String ex : exceptionList) { + // a correct run shouldn't deliver any exception + counterExceptions++; + System.out.println(ex); + } + System.out.println("The List dateList contains " + counterDateValues + " date values"); + System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); + } +} diff --git a/tls/src/main/java/com/iluwatar/tls/AppUgly.java b/tls/src/main/java/com/iluwatar/tls/AppUgly.java new file mode 100644 index 000000000..7025d42b7 --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/AppUgly.java @@ -0,0 +1,112 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + * + * This App shows an example for problems with global thread variables. A global + * thread variable is a variable defined as class variable of a + * XyzRunnable-Class. In this example in the class + * {@link DateFormatUglyRunnable} + *

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

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

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

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

+ * And even without Exceptions the run may not deliver the correct results. + * All date values should be the same after the run. Check it + * + */ +public class AppUgly { + // A list to collect the date values created in the the threads + static List dateList = Collections.synchronizedList(new ArrayList()); + // A list to collect Exceptions thrown in the threads + static List exceptionList = Collections.synchronizedList(new ArrayList()); + + /** + * Program entry point + * + * @param args + * command line args + */ + public static void main(String[] args) { + int counterDateValues = 0; + int counterExceptions = 0; + + // Prepare the Runnable + DateFormatUglyRunnable runnableDf = new DateFormatUglyRunnable("dd/MM/yyyy", "15/12/2015"); + + // 4 threads using the same Runnable + Thread t1 = new Thread(runnableDf); + Thread t2 = new Thread(runnableDf); + Thread t3 = new Thread(runnableDf); + Thread t4 = new Thread(runnableDf); + t1.start(); + t2.start(); + t3.start(); + t4.start(); + try { + t1.join(); + t2.join(); + t3.join(); + t4.join(); + } catch (InterruptedException e) { + // Action not coded here + } + for (Date dt : dateList) { + // a correct run should deliver 20 times 15.12.2015 + counterDateValues++; + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + // Formatted output of the date value: DD.MM.YYYY + System.out.println(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + for (String ex : exceptionList) { + // a correct run shouldn't deliver any exception + counterExceptions++; + System.out.println(ex); + } + System.out.println("The List dateList contains " + counterDateValues + " date values"); + System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); + } +} diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java new file mode 100644 index 000000000..d2009d21b --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java @@ -0,0 +1,84 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +/** + * DateFormatRunnable converts string dates to a date format using + * SimpleDateFormat The date format and the date value will be passed to the + * Runnable by the constructor. The constructor creates a instance of + * SimpleDateFormat and stores it in a ThreadLocal class variable. For the + * complete description of the example see {@link App} + * + */ +public class DateFormatRunnable implements Runnable { + // class variables (members) + private ThreadLocal df; + private String dateValue; // for date Value Thread Local not needed + + /** + * The date format and the date value are passed to the constructor + * + * @param inDateFormat + * string date format string, e.g. "dd/MM/yyyy" + * @param inDateValue + * string date value, e.g. "21/06/2016" + */ + public DateFormatRunnable(String inDateFormat, String inDateValue) { + final String idf = inDateFormat; + this.df = new ThreadLocal() { + @Override + protected DateFormat initialValue() { + return new SimpleDateFormat(idf); + } + }; + this.dateValue = inDateValue; + } + + /** + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + System.out.println(Thread.currentThread() + " started executing..."); + + // Convert date value to date 5 times + for (int i = 1; i <= 5; i++) { + try { + // this is the statement where it is important to have the + // instance of SimpleDateFormat locally + // Create the date value and store it in dateList + App.dateList.add(this.df.get().parse(this.dateValue)); + } catch (Exception e) { + // write the Exception to a list and continue work + App.exceptionList.add(e.getClass() + ": " + e.getMessage()); + } + + } + + System.out.println(Thread.currentThread() + " finished executing"); + } +} diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java new file mode 100644 index 000000000..ca883a913 --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java @@ -0,0 +1,76 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +/** + * DateFormatUglyRunnable converts string dates to a date format using + * SimpleDateFormat. The date value and the date format will be passed to the + * Runnable by the constructor. The constructor creates an instance of + * SimpleDateFormat and stores it in a class variable. For the complete + * description of the example see {@link AppUgly} + * + */ +public class DateFormatUglyRunnable implements Runnable { + // class variables (members) + private DateFormat df; + private String dateValue; + + /** + * The date format and the date value are passed to the constructor + * + * @param inDateFormat + * string date format string, e.g. "dd/MM/yyyy" + * @param inDateValue + * string date value, e.g. "21/06/2016" + */ + public DateFormatUglyRunnable(String inDateFormat, String inDateValue) { + this.df = new SimpleDateFormat(inDateFormat); + this.dateValue = inDateValue; + } + + /** + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + System.out.println(Thread.currentThread() + " started executing..."); + + // Convert date value to date 5 times + for (int i = 1; i <= 5; i++) { + try { + // Create the date value and store it in dateList + AppUgly.dateList.add(this.df.parse(this.dateValue)); + } catch (Exception e) { + // write the Exception to a list and continue work + AppUgly.exceptionList.add(e.getClass() + ": " + e.getMessage()); + } + + } + + System.out.println(Thread.currentThread() + " finished executing"); + } +} From 544f7fb6d1be97409cc193cad6010a7478550a27 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:28:02 +0100 Subject: [PATCH 04/40] delete empty file --- tls/src/main/java/com/iluwatar/tls/test | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/test diff --git a/tls/src/main/java/com/iluwatar/tls/test b/tls/src/main/java/com/iluwatar/tls/test deleted file mode 100644 index 1df28a22d..000000000 --- a/tls/src/main/java/com/iluwatar/tls/test +++ /dev/null @@ -1 +0,0 @@ -ss From 15d660b117d3ad6cdac4c7ebd221e6d611527841 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:30:22 +0100 Subject: [PATCH 05/40] empty file to create folder --- tls/src/test/java/com/iluwatar/tls/test | 1 + 1 file changed, 1 insertion(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/test diff --git a/tls/src/test/java/com/iluwatar/tls/test b/tls/src/test/java/com/iluwatar/tls/test new file mode 100644 index 000000000..a302060fe --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/test @@ -0,0 +1 @@ +kk From e64f7faa3fabd17e6451fabde709f41de0f9f981 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:31:20 +0100 Subject: [PATCH 06/40] upload junit test --- .../test/java/com/iluwatar/tls/AppTest.java | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/AppTest.java diff --git a/tls/src/test/java/com/iluwatar/tls/AppTest.java b/tls/src/test/java/com/iluwatar/tls/AppTest.java new file mode 100644 index 000000000..09bb72c93 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/AppTest.java @@ -0,0 +1,134 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * + * Application test + * + * In this test {@link App} is executed. After the run of App the converted Data is available in + * the static lists created by the run of the app. + *

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

+ * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + */ +public class AppTest { + + // Class variables used in setup() have to be static because the Compiler wants the + // setup() method to be static + /** + * Number of date values in the list created by the run of App. Will be set in setup() + */ + static int actualCounterDateValues = 0; + + /** + * Number of exceptions in the list created by the run of App. Will be set in setup() + */ + static int actualCounterExceptions = 0; + + /** + * The date values created by the run of App. List will be filled in the setup() method + */ + static List actualDateValues = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of App + */ + int expectedCounterDateValues = 20; + + /** + * Expected number of exceptions in the exception list created by the run of App. + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by the run of App + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", + "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", + "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run App. After this run the result is available in the static lists + */ + @BeforeClass + public static void setup() { + String[] args = {}; + App.main(args); + + // Prepare data created by the run of App for the tests + for (Date dt : App.dateList) { + actualCounterDateValues++; + // a correct run should deliver 20 times 15.12.2015 + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + // Convert date value to string format DD.MM.YYYY + actualDateValues.add( + cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); + } + for (@SuppressWarnings("unused") String exc : App.exceptionList) { + actualCounterExceptions++; + // a correct run should no exceptions + } + } + + /** + * Test date values after run of App. A correct run should deliver 20 times 15.12.2015 + */ + @Test + public void testDateValues() { + assertEquals(expectedDateValues, actualDateValues); + } + + /** + * Test number of dates in list after und of App. A correct run should deliver 20 date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, actualCounterDateValues); + } + + /** + * Test number of Exceptions in list after und of App. A correct run should deliver no exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, actualCounterExceptions); + } +} From 803a97237cc140fee4ac327a7af341d56d8f28a1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:31:53 +0100 Subject: [PATCH 07/40] delete empty file --- tls/test | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tls/test diff --git a/tls/test b/tls/test deleted file mode 100644 index e8689b24f..000000000 --- a/tls/test +++ /dev/null @@ -1 +0,0 @@ -hh From 937a1e269d131532b37275678cc09d5a4827d280 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:32:13 +0100 Subject: [PATCH 08/40] delete empty file --- tls/src/test/java/com/iluwatar/tls/test | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/test diff --git a/tls/src/test/java/com/iluwatar/tls/test b/tls/src/test/java/com/iluwatar/tls/test deleted file mode 100644 index a302060fe..000000000 --- a/tls/src/test/java/com/iluwatar/tls/test +++ /dev/null @@ -1 +0,0 @@ -kk From e17cf27e5ae25cbc44b6eb48b9bac239f1352e80 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 15 Dec 2016 18:33:52 +0100 Subject: [PATCH 09/40] upload pom.xml --- tls/pom.xml | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tls/pom.xml diff --git a/tls/pom.xml b/tls/pom.xml new file mode 100644 index 000000000..68ebcdbf1 --- /dev/null +++ b/tls/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.14.0-SNAPSHOT + + tls + + + junit + junit + test + + + From 9b7ce556e3339e2976d44efa20640c1440636886 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 16 Dec 2016 09:35:19 +0100 Subject: [PATCH 10/40] Create emptyfile --- tls/etc/emptyfile | 1 + 1 file changed, 1 insertion(+) create mode 100644 tls/etc/emptyfile diff --git a/tls/etc/emptyfile b/tls/etc/emptyfile new file mode 100644 index 000000000..aa2fc61b2 --- /dev/null +++ b/tls/etc/emptyfile @@ -0,0 +1 @@ +jj From 487f9ddc80f20dc93e69c86ea866845b95f70e36 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 16 Dec 2016 09:42:08 +0100 Subject: [PATCH 11/40] Add files via upload --- tls/etc/tls.urm.puml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tls/etc/tls.urm.puml diff --git a/tls/etc/tls.urm.puml b/tls/etc/tls.urm.puml new file mode 100644 index 000000000..6425b7d33 --- /dev/null +++ b/tls/etc/tls.urm.puml @@ -0,0 +1,28 @@ +@startuml +package com.iluwatar.tls { + class App { + ~ dateList : List {static} + ~ exceptionList : List {static} + + App() + + main(args : String[]) {static} + } + class AppUgly { + ~ dateList : List {static} + ~ exceptionList : List {static} + + AppUgly() + + main(args : String[]) {static} + } + class DateFormatRunnable { + - dateValue : String + - df : ThreadLocal + + DateFormatRunnable(inDateFormat : String, inDateValue : String) + + run() + } + class DateFormatUglyRunnable { + - dateValue : String + - df : DateFormat + + DateFormatUglyRunnable(inDateFormat : String, inDateValue : String) + + run() + } +} +@enduml \ No newline at end of file From 61b135697652d056bd0c6704d1b5ff0206964bcb Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 16 Dec 2016 09:42:46 +0100 Subject: [PATCH 12/40] Delete emptyfile --- tls/etc/emptyfile | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tls/etc/emptyfile diff --git a/tls/etc/emptyfile b/tls/etc/emptyfile deleted file mode 100644 index aa2fc61b2..000000000 --- a/tls/etc/emptyfile +++ /dev/null @@ -1 +0,0 @@ -jj From c8b3c773c787fc143e60415de35eca49502e1cad Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 16 Dec 2016 09:43:16 +0100 Subject: [PATCH 13/40] Add files via upload --- tls/etc/tls.ucls | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tls/etc/tls.ucls diff --git a/tls/etc/tls.ucls b/tls/etc/tls.ucls new file mode 100644 index 000000000..5e21929e2 --- /dev/null +++ b/tls/etc/tls.ucls @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From fb98da86c4a3984415e88f3154e291725219ddbb Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 16 Dec 2016 11:12:43 +0100 Subject: [PATCH 14/40] Add files via upload --- tls/etc/tls.png | Bin 0 -> 10307 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tls/etc/tls.png diff --git a/tls/etc/tls.png b/tls/etc/tls.png new file mode 100644 index 0000000000000000000000000000000000000000..bedea6cc8bc4eaff9f9f6d32f7b696f3123a756b GIT binary patch literal 10307 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 literal 0 HcmV?d00001 From e210e4ed627468d19652cc8c195ca503917ee86c Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 16 Dec 2016 11:17:27 +0100 Subject: [PATCH 15/40] Add files via upload --- tls/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tls/README.md diff --git a/tls/README.md b/tls/README.md new file mode 100644 index 000000000..53db18400 --- /dev/null +++ b/tls/README.md @@ -0,0 +1,22 @@ +--- +layout: pattern +title: Thread Local Storage +folder: tls +permalink: /patterns/tls/ +pumlid: 5Sd13OGm30NHLg00uZlTc62HeCI9x6-s_ONJF6dMghd5AM5jAS3qdSZubwwA4aUuM1uAKQGyEg6CpZxSwUQ7jrEyNhfD1iJKwNql2Cr9aB-ci9vczFO7 +categories: Concurrency +tags: + - Java + - Difficulty-Intermediate +--- + +## Intent +Securing variables global to a thread, i.e. class variables of the Runnable object, +against being spoiled by other threads using the same instance of the Runnable object + +![alt text](./etc/tls.png "Thread Local Storage") + +## Applicability +Use the Thread Local Storage in any of the following situations + +* when you use class variables in your Runnable Object that are not read-only From 26b79a5382dfa22f7ffb22eb7acdf71918e75e6f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:16:45 +0100 Subject: [PATCH 16/40] Update README.md Some additonal description, deleted wrong pumlid --- tls/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tls/README.md b/tls/README.md index 53db18400..9503267df 100644 --- a/tls/README.md +++ b/tls/README.md @@ -3,7 +3,7 @@ layout: pattern title: Thread Local Storage folder: tls permalink: /patterns/tls/ -pumlid: 5Sd13OGm30NHLg00uZlTc62HeCI9x6-s_ONJF6dMghd5AM5jAS3qdSZubwwA4aUuM1uAKQGyEg6CpZxSwUQ7jrEyNhfD1iJKwNql2Cr9aB-ci9vczFO7 +pumlid: categories: Concurrency tags: - Java @@ -11,12 +11,13 @@ tags: --- ## Intent -Securing variables global to a thread, i.e. class variables of the Runnable object, -against being spoiled by other threads using the same instance of the Runnable object +Securing variables global to a thread, i.e. class variables if a Callable object, +against being spoiled by other threads using the same instance of the Callable object ![alt text](./etc/tls.png "Thread Local Storage") ## Applicability Use the Thread Local Storage in any of the following situations -* when you use class variables in your Runnable Object that are not read-only +* when you use class variables in your Callable Object that are not read-only and you use the same Callable instance in more than one thread running in parallel +* when you use static variables in your Callable Object that are not read-only and more than one instances of the Callable may run in parallel threads. From e8fc3427c6b982d4b670024ea5ee70bb254db84b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:23:33 +0100 Subject: [PATCH 17/40] Update README.md no change of content. Improved text --- tls/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tls/README.md b/tls/README.md index 9503267df..904d7ee05 100644 --- a/tls/README.md +++ b/tls/README.md @@ -11,13 +11,12 @@ tags: --- ## Intent -Securing variables global to a thread, i.e. class variables if a Callable object, -against being spoiled by other threads using the same instance of the Callable object +Securing variables global to a thread against being spoiled by other threads. That is needed if you use class variables or static variables in your Callable object or Runnable object that are not read-only. ![alt text](./etc/tls.png "Thread Local Storage") ## Applicability Use the Thread Local Storage in any of the following situations -* when you use class variables in your Callable Object that are not read-only and you use the same Callable instance in more than one thread running in parallel -* when you use static variables in your Callable Object that are not read-only and more than one instances of the Callable may run in parallel threads. +* when you use class variables in your Callable / Runnalbe object that are not read-only and you use the same Callable instance in more than one thread running in parallel +* when you use static variables in your Callable / Runnable object that are not read-only and more than one instances of the Callable / Runnalbe may run in parallel threads. From c167f87ce5eeb3060ee708a160d15b9878e211bc Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:27:46 +0100 Subject: [PATCH 18/40] Delete tls.png --- tls/etc/tls.png | Bin 10307 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tls/etc/tls.png diff --git a/tls/etc/tls.png b/tls/etc/tls.png deleted file mode 100644 index bedea6cc8bc4eaff9f9f6d32f7b696f3123a756b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10307 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 From 3342851005e337be6f0a2e69495ab62ab788034d Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:28:17 +0100 Subject: [PATCH 19/40] Delete tls.ucls --- tls/etc/tls.ucls | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 tls/etc/tls.ucls diff --git a/tls/etc/tls.ucls b/tls/etc/tls.ucls deleted file mode 100644 index 5e21929e2..000000000 --- a/tls/etc/tls.ucls +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From c529e35791dce7c4dc78799928f24a67982eb2b1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:28:27 +0100 Subject: [PATCH 20/40] Delete tls.urm.puml --- tls/etc/tls.urm.puml | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 tls/etc/tls.urm.puml diff --git a/tls/etc/tls.urm.puml b/tls/etc/tls.urm.puml deleted file mode 100644 index 6425b7d33..000000000 --- a/tls/etc/tls.urm.puml +++ /dev/null @@ -1,28 +0,0 @@ -@startuml -package com.iluwatar.tls { - class App { - ~ dateList : List {static} - ~ exceptionList : List {static} - + App() - + main(args : String[]) {static} - } - class AppUgly { - ~ dateList : List {static} - ~ exceptionList : List {static} - + AppUgly() - + main(args : String[]) {static} - } - class DateFormatRunnable { - - dateValue : String - - df : ThreadLocal - + DateFormatRunnable(inDateFormat : String, inDateValue : String) - + run() - } - class DateFormatUglyRunnable { - - dateValue : String - - df : DateFormat - + DateFormatUglyRunnable(inDateFormat : String, inDateValue : String) - + run() - } -} -@enduml \ No newline at end of file From 65e047974c0bdaad2f93f89bb6d3994424f85f51 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:29:19 +0100 Subject: [PATCH 21/40] Create empty --- tls/etc/empty | 1 + 1 file changed, 1 insertion(+) create mode 100644 tls/etc/empty diff --git a/tls/etc/empty b/tls/etc/empty new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/tls/etc/empty @@ -0,0 +1 @@ + From 15913d6382d8baada2349e5dad1041ef4826c962 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:31:06 +0100 Subject: [PATCH 22/40] Add files via upload new uml diagramm after changes to the java classes --- tls/etc/tls.png | Bin 0 -> 34509 bytes tls/etc/tls.ucls | 79 +++++++++++++++++++++++++++++++++++++++++++ tls/etc/tls.urm.puml | 23 +++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 tls/etc/tls.png create mode 100644 tls/etc/tls.ucls create mode 100644 tls/etc/tls.urm.puml diff --git a/tls/etc/tls.png b/tls/etc/tls.png new file mode 100644 index 0000000000000000000000000000000000000000..442f39a0c730b6db350e1a2e0bffba1a2a60e8da GIT binary patch literal 34509 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 Su=8Tx-<3k&DUf*V`+op$;IV=L literal 0 HcmV?d00001 diff --git a/tls/etc/tls.ucls b/tls/etc/tls.ucls new file mode 100644 index 000000000..bd238346d --- /dev/null +++ b/tls/etc/tls.ucls @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tls/etc/tls.urm.puml b/tls/etc/tls.urm.puml new file mode 100644 index 000000000..d2eedb371 --- /dev/null +++ b/tls/etc/tls.urm.puml @@ -0,0 +1,23 @@ +@startuml +package com.iluwatar.tls { + class App { + + App() + + main(args : String[]) {static} + - printAndCountDates(res : Result) : int {static} + - printAndCountExceptions(res : Result) : int {static} + } + class DateFormatCallable { + - dateValue : String + - df : ThreadLocal + + DateFormatCallable(inDateFormat : String, inDateValue : String) + + call() : Result + } + class Result { + - dateList : List + - exceptionList : List + + Result() + + getDateList() : List + + getExceptionList() : List + } +} +@enduml \ No newline at end of file From 283f198ba89b7c003ce54ba7f49c95f751731bd6 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:32:26 +0100 Subject: [PATCH 23/40] Delete empty --- tls/etc/empty | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tls/etc/empty diff --git a/tls/etc/empty b/tls/etc/empty deleted file mode 100644 index 8b1378917..000000000 --- a/tls/etc/empty +++ /dev/null @@ -1 +0,0 @@ - From ed11c4c4f94a24b7ded3fdc22f79bc843516800a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:33:40 +0100 Subject: [PATCH 24/40] Delete App.java --- tls/src/main/java/com/iluwatar/tls/App.java | 108 -------------------- 1 file changed, 108 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/App.java diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java deleted file mode 100644 index b16aa1fc6..000000000 --- a/tls/src/main/java/com/iluwatar/tls/App.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.List; - -/** - * ThreadLocal pattern - *

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

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

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

- * SimpleDateFormat is one of the basic Java classes and is not thread-safe. If - * you do not isolate the instance of SimpleDateFormat per each thread then - * problems arise. These problems are described with the example {@link AppUgly} - * - */ -public class App { - // A list to collect the date values created in the the threads - static List dateList = Collections.synchronizedList(new ArrayList()); - - // A list to collect Exceptions thrown in the threads (should be none in - // this example) - static List exceptionList = Collections.synchronizedList(new ArrayList()); - - /** - * Program entry point - * - * @param args - * command line args - */ - public static void main(String[] args) { - int counterDateValues = 0; - int counterExceptions = 0; - - // Create a runnable - DateFormatRunnable runnableDf = new DateFormatRunnable("dd/MM/yyyy", "15/12/2015"); - // start 4 threads, each using the same Runnable instance - Thread t1 = new Thread(runnableDf); - Thread t2 = new Thread(runnableDf); - Thread t3 = new Thread(runnableDf); - Thread t4 = new Thread(runnableDf); - t1.start(); - t2.start(); - t3.start(); - t4.start(); - try { - t1.join(); - t2.join(); - t3.join(); - t4.join(); - } catch (InterruptedException e) { - // Action not coded here - } - for (Date dt : dateList) { - // a correct run should deliver 20 times 15.12.2015 - counterDateValues++; - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - // Formatted output of the date value: DD.MM.YYYY - System.out.println( - cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); - } - for (String ex : exceptionList) { - // a correct run shouldn't deliver any exception - counterExceptions++; - System.out.println(ex); - } - System.out.println("The List dateList contains " + counterDateValues + " date values"); - System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); - } -} From c5987485498a17998b97c4083323e11cb6a9a40a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:33:59 +0100 Subject: [PATCH 25/40] Delete AppUgly.java --- .../main/java/com/iluwatar/tls/AppUgly.java | 112 ------------------ 1 file changed, 112 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/AppUgly.java diff --git a/tls/src/main/java/com/iluwatar/tls/AppUgly.java b/tls/src/main/java/com/iluwatar/tls/AppUgly.java deleted file mode 100644 index 7025d42b7..000000000 --- a/tls/src/main/java/com/iluwatar/tls/AppUgly.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.List; - -/** - * - * This App shows an example for problems with global thread variables. A global - * thread variable is a variable defined as class variable of a - * XyzRunnable-Class. In this example in the class - * {@link DateFormatUglyRunnable} - *

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

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

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

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

- * And even without Exceptions the run may not deliver the correct results. - * All date values should be the same after the run. Check it - * - */ -public class AppUgly { - // A list to collect the date values created in the the threads - static List dateList = Collections.synchronizedList(new ArrayList()); - // A list to collect Exceptions thrown in the threads - static List exceptionList = Collections.synchronizedList(new ArrayList()); - - /** - * Program entry point - * - * @param args - * command line args - */ - public static void main(String[] args) { - int counterDateValues = 0; - int counterExceptions = 0; - - // Prepare the Runnable - DateFormatUglyRunnable runnableDf = new DateFormatUglyRunnable("dd/MM/yyyy", "15/12/2015"); - - // 4 threads using the same Runnable - Thread t1 = new Thread(runnableDf); - Thread t2 = new Thread(runnableDf); - Thread t3 = new Thread(runnableDf); - Thread t4 = new Thread(runnableDf); - t1.start(); - t2.start(); - t3.start(); - t4.start(); - try { - t1.join(); - t2.join(); - t3.join(); - t4.join(); - } catch (InterruptedException e) { - // Action not coded here - } - for (Date dt : dateList) { - // a correct run should deliver 20 times 15.12.2015 - counterDateValues++; - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - // Formatted output of the date value: DD.MM.YYYY - System.out.println(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); - } - for (String ex : exceptionList) { - // a correct run shouldn't deliver any exception - counterExceptions++; - System.out.println(ex); - } - System.out.println("The List dateList contains " + counterDateValues + " date values"); - System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); - } -} From f170aaa42b2fafb9e6162810a3f529b5b114c499 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:34:12 +0100 Subject: [PATCH 26/40] Delete DateFormatRunnable.java --- .../com/iluwatar/tls/DateFormatRunnable.java | 84 ------------------- 1 file changed, 84 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java deleted file mode 100644 index d2009d21b..000000000 --- a/tls/src/main/java/com/iluwatar/tls/DateFormatRunnable.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; - -/** - * DateFormatRunnable converts string dates to a date format using - * SimpleDateFormat The date format and the date value will be passed to the - * Runnable by the constructor. The constructor creates a instance of - * SimpleDateFormat and stores it in a ThreadLocal class variable. For the - * complete description of the example see {@link App} - * - */ -public class DateFormatRunnable implements Runnable { - // class variables (members) - private ThreadLocal df; - private String dateValue; // for date Value Thread Local not needed - - /** - * The date format and the date value are passed to the constructor - * - * @param inDateFormat - * string date format string, e.g. "dd/MM/yyyy" - * @param inDateValue - * string date value, e.g. "21/06/2016" - */ - public DateFormatRunnable(String inDateFormat, String inDateValue) { - final String idf = inDateFormat; - this.df = new ThreadLocal() { - @Override - protected DateFormat initialValue() { - return new SimpleDateFormat(idf); - } - }; - this.dateValue = inDateValue; - } - - /** - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - System.out.println(Thread.currentThread() + " started executing..."); - - // Convert date value to date 5 times - for (int i = 1; i <= 5; i++) { - try { - // this is the statement where it is important to have the - // instance of SimpleDateFormat locally - // Create the date value and store it in dateList - App.dateList.add(this.df.get().parse(this.dateValue)); - } catch (Exception e) { - // write the Exception to a list and continue work - App.exceptionList.add(e.getClass() + ": " + e.getMessage()); - } - - } - - System.out.println(Thread.currentThread() + " finished executing"); - } -} From 7200329a6b05d1c54ec7f4cd89235199d29c4e5e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:38:20 +0100 Subject: [PATCH 27/40] Add files via upload Rework replaces previous version completely. Using ExecutorService. Use of result object instead of static variables. Ugly example is left out. --- tls/src/main/java/com/iluwatar/tls/App.java | 146 ++++++++++++++++++ .../com/iluwatar/tls/DateFormatCallable.java | 98 ++++++++++++ .../main/java/com/iluwatar/tls/Result.java | 40 +++++ 3 files changed, 284 insertions(+) create mode 100644 tls/src/main/java/com/iluwatar/tls/App.java create mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java create mode 100644 tls/src/main/java/com/iluwatar/tls/Result.java diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java new file mode 100644 index 000000000..80e87042c --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/App.java @@ -0,0 +1,146 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * ThreadLocal pattern + *

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

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

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

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

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

+ * This example clearly show what will happen when using non thread-safe classes + * in a thread. In real life this may happen one in of 1.000 or 10.000 conversions + * and those are really hard to find errors. + * + * @author Thomas Bauer, 2017 + */ +public class App { + /** + * Program entry point + * + * @param args + * command line args + */ + public static void main(String[] args) { + int counterDateValues = 0; + int counterExceptions = 0; + + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start 4 threads, each using the same Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + + Future futureResult1 = executor.submit(callableDf); + Future futureResult2 = executor.submit(callableDf); + Future futureResult3 = executor.submit(callableDf); + Future futureResult4 = executor.submit(callableDf); + try { + Result[] result = new Result[4]; + result[0] = futureResult1.get(); + result[1] = futureResult2.get(); + result[2] = futureResult3.get(); + result[3] = futureResult4.get(); + + // Print results of thread executions (converted dates and raised exceptions) + // and count them + for (int i = 0; i < result.length; i++) { + counterDateValues = counterDateValues + printAndCountDates(result[i]); + counterExceptions = counterExceptions + printAndCountExceptions(result[i]); + } + + // a correct run should deliver 20 times 15.12.2015 + // and a correct run shouldn't deliver any exception + System.out.println("The List dateList contains " + counterDateValues + " date values"); + System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); + + } catch (Exception e) { + // no action here + } + executor.shutdown(); + } + + /** + * Print result (date values) of a thread execution and count dates + * + * @param res contains results of a thread execution + */ + private static int printAndCountDates(Result res) { + // a correct run should deliver 5 times 15.12.2015 per each thread + int counter = 0; + for (Date dt : res.getDateList()) { + counter++; + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + // Formatted output of the date value: DD.MM.YYYY + System.out.println( + cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); + } + return counter; + } + + /** + * Print result (exceptions) of a thread execution and count exceptions + * + * @param res contains results of a thread execution + * @return number of dates + */ + private static int printAndCountExceptions(Result res) { + // a correct run shouldn't deliver any exception + int counter = 0; + for (String ex : res.getExceptionList()) { + counter++; + System.out.println(ex); + } + return counter; + } +} diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java new file mode 100644 index 000000000..a28e24d4e --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/DateFormatCallable.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.concurrent.Callable; + +/** + * DateFormatCallable converts string dates to a date format using + * SimpleDateFormat. The date format and the date value will be passed to the + * Callable by the constructor. The constructor creates a instance of + * SimpleDateFormat and stores it in a ThreadLocal class variable. For the + * complete description of the example see {@link App} + * + * You can comment out the code marked with //TLTL and comment in the + * code marked //NTLNTL. Then you can see what will happen if you do not + * use the ThreadLocal. For details see the description of {@link App} + * + * @author Thomas Bauer, 2017 + */ +public class DateFormatCallable implements Callable { + // class variables (members) + private ThreadLocal df; //TLTL + // private DateFormat df; //NTLNTL + + private String dateValue; // for dateValue Thread Local not needed + + + /** + * The date format and the date value are passed to the constructor + * + * @param inDateFormat + * string date format string, e.g. "dd/MM/yyyy" + * @param inDateValue + * string date value, e.g. "21/06/2016" + */ + public DateFormatCallable(String inDateFormat, String inDateValue) { + final String idf = inDateFormat; //TLTL + this.df = new ThreadLocal() { //TLTL + @Override //TLTL + protected DateFormat initialValue() { //TLTL + return new SimpleDateFormat(idf); //TLTL + } //TLTL + }; //TLTL + // this.df = new SimpleDateFormat(inDateFormat); //NTLNTL + this.dateValue = inDateValue; + } + + /** + * @see java.util.concurrent.Callable#call() + */ + @Override + public Result call() { + System.out.println(Thread.currentThread() + " started executing..."); + Result result = new Result(); + + // Convert date value to date 5 times + for (int i = 1; i <= 5; i++) { + try { + // this is the statement where it is important to have the + // instance of SimpleDateFormat locally + // Create the date value and store it in dateList + result.getDateList().add(this.df.get().parse(this.dateValue)); //TLTL +// result.getDateList().add(this.df.parse(this.dateValue)); //NTLNTL + } catch (Exception e) { + // write the Exception to a list and continue work + result.getExceptionList().add(e.getClass() + ": " + e.getMessage()); + } + + } + + System.out.println(Thread.currentThread() + " finished processing part of the thread"); + + return result; + } +} diff --git a/tls/src/main/java/com/iluwatar/tls/Result.java b/tls/src/main/java/com/iluwatar/tls/Result.java new file mode 100644 index 000000000..951a02a2f --- /dev/null +++ b/tls/src/main/java/com/iluwatar/tls/Result.java @@ -0,0 +1,40 @@ +/* + * Fiducia IT AG, All rights reserved. Use is subject to license terms. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Result object that will be returned by the Callable {@link DateFormatCallable} + * used in {@link App} + * + * @author Thomas Bauer, 2017 + */ +public class Result { + // A list to collect the date values created in one thread + private List dateList = new ArrayList(); + + // A list to collect Exceptions thrown in one threads (should be none in + // this example) + private List exceptionList = new ArrayList(); + + /** + * + * @return List of date values collected within an thread execution + */ + public List getDateList() { + return dateList; + } + + /** + * + * @return List of exceptions thrown within an thread execution + */ + public List getExceptionList() { + return exceptionList; + } +} From 080965fb176f3156744fad4f3ab004e562bb1615 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:38:49 +0100 Subject: [PATCH 28/40] Delete DateFormatUglyRunnable.java --- .../iluwatar/tls/DateFormatUglyRunnable.java | 76 ------------------- 1 file changed, 76 deletions(-) delete mode 100644 tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java diff --git a/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java b/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java deleted file mode 100644 index ca883a913..000000000 --- a/tls/src/main/java/com/iluwatar/tls/DateFormatUglyRunnable.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; - -/** - * DateFormatUglyRunnable converts string dates to a date format using - * SimpleDateFormat. The date value and the date format will be passed to the - * Runnable by the constructor. The constructor creates an instance of - * SimpleDateFormat and stores it in a class variable. For the complete - * description of the example see {@link AppUgly} - * - */ -public class DateFormatUglyRunnable implements Runnable { - // class variables (members) - private DateFormat df; - private String dateValue; - - /** - * The date format and the date value are passed to the constructor - * - * @param inDateFormat - * string date format string, e.g. "dd/MM/yyyy" - * @param inDateValue - * string date value, e.g. "21/06/2016" - */ - public DateFormatUglyRunnable(String inDateFormat, String inDateValue) { - this.df = new SimpleDateFormat(inDateFormat); - this.dateValue = inDateValue; - } - - /** - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - System.out.println(Thread.currentThread() + " started executing..."); - - // Convert date value to date 5 times - for (int i = 1; i <= 5; i++) { - try { - // Create the date value and store it in dateList - AppUgly.dateList.add(this.df.parse(this.dateValue)); - } catch (Exception e) { - // write the Exception to a list and continue work - AppUgly.exceptionList.add(e.getClass() + ": " + e.getMessage()); - } - - } - - System.out.println(Thread.currentThread() + " finished executing"); - } -} From a8e2c157ded06ef6d149fa617e6cd4e9a1ce6a8f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:41:13 +0100 Subject: [PATCH 29/40] Add files via upload Test reworked completely. AppTest seperated. --- .../iluwatar/tls/DateFormatRunnableTest.java | 144 +++++++++++++++ ...FormatRunnableTestIncorrectDateFormat.java | 127 ++++++++++++++ .../DateFormatRunnableTestMultiThread.java | 164 ++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java new file mode 100644 index 000000000..d6105dc98 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java @@ -0,0 +1,144 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

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

+ * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatRunnableTest { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdDateValues = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by the run of DateFormatRunnalbe + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + createdDateValues = convertDatesToString(result); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new ArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + */ + @Test + public void testDateValues() { + assertEquals(expectedDateValues, createdDateValues); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver 5 date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should deliver + * no exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java new file mode 100644 index 000000000..bae89f160 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java @@ -0,0 +1,127 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

+ * An incorrect formatted date is passed to the Callable + * After a successful run 0 date values and 5 exceptions should be in the result object. + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatRunnableTestIncorrectDateFormat { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdExceptions = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 0; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 5; + + /** + * Expected content of the list containing the exceptions created by the run of DateFormatRunnalbe + */ + List expectedExceptions = Arrays.asList("class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\""); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable. Pass a string date value not matching the format string + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15.12.2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + /** + * Test Exceptions after the run of DateFormatRunnalbe. A correct run should deliver 5 times the + * same exception + */ + @Test + public void testExecptions() { + assertEquals(expectedExceptions, result.getExceptionList()); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver no date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java new file mode 100644 index 000000000..354915209 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java @@ -0,0 +1,164 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is used by 4 threads in parallel + *

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

+ * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatRunnableTestMultiThread { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable, one for each thread + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result[] result = new Result[4]; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + @SuppressWarnings("serial") + static class StringArrayList extends ArrayList { + /* nothing needed here */ + } + static List[] createdDateValues = new StringArrayList[4]; + + /** + * Expected number of date values in the date value list created by each thread + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by each thread + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by each thread + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult1 = executor.submit(callableDf); + Future futureResult2 = executor.submit(callableDf); + Future futureResult3 = executor.submit(callableDf); + Future futureResult4 = executor.submit(callableDf); + try { + result[0] = futureResult1.get(); + result[1] = futureResult2.get(); + result[2] = futureResult3.get(); + result[3] = futureResult4.get(); + for (int i = 0; i < result.length; i++) { + createdDateValues[i] = convertDatesToString(result[i]); + } + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new StringArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + * by each thread + */ + @Test + public void testDateValues() { + for (int i = 0; i < createdDateValues.length; i++) { + assertEquals(expectedDateValues, createdDateValues[i]); + } + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 date values by each thread + */ + @Test + public void testCounterDateValues() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterDateValues, result[i].getDateList().size()); + } + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver no exceptions + */ + @Test + public void testCounterExceptions() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterExceptions, result[i].getExceptionList().size()); + } + } +} From 453862cfc258539447568ad6459059e09829502e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:41:46 +0100 Subject: [PATCH 30/40] Delete AppTest.java --- .../test/java/com/iluwatar/tls/AppTest.java | 134 ------------------ 1 file changed, 134 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/AppTest.java diff --git a/tls/src/test/java/com/iluwatar/tls/AppTest.java b/tls/src/test/java/com/iluwatar/tls/AppTest.java deleted file mode 100644 index 09bb72c93..000000000 --- a/tls/src/test/java/com/iluwatar/tls/AppTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; - -/** - * - * Application test - * - * In this test {@link App} is executed. After the run of App the converted Data is available in - * the static lists created by the run of the app. - *

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

- * Additionally the number of list entries are tested for both the list with the date values - * and the list with the exceptions - * - */ -public class AppTest { - - // Class variables used in setup() have to be static because the Compiler wants the - // setup() method to be static - /** - * Number of date values in the list created by the run of App. Will be set in setup() - */ - static int actualCounterDateValues = 0; - - /** - * Number of exceptions in the list created by the run of App. Will be set in setup() - */ - static int actualCounterExceptions = 0; - - /** - * The date values created by the run of App. List will be filled in the setup() method - */ - static List actualDateValues = new ArrayList(); - - /** - * Expected number of date values in the date value list created by the run of App - */ - int expectedCounterDateValues = 20; - - /** - * Expected number of exceptions in the exception list created by the run of App. - */ - int expectedCounterExceptions = 0; - - /** - * Expected content of the list containing the date values created by the run of App - */ - List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", - "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", - "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); - - /** - * Run App. After this run the result is available in the static lists - */ - @BeforeClass - public static void setup() { - String[] args = {}; - App.main(args); - - // Prepare data created by the run of App for the tests - for (Date dt : App.dateList) { - actualCounterDateValues++; - // a correct run should deliver 20 times 15.12.2015 - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - // Convert date value to string format DD.MM.YYYY - actualDateValues.add( - cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + +cal.get(Calendar.YEAR)); - } - for (@SuppressWarnings("unused") String exc : App.exceptionList) { - actualCounterExceptions++; - // a correct run should no exceptions - } - } - - /** - * Test date values after run of App. A correct run should deliver 20 times 15.12.2015 - */ - @Test - public void testDateValues() { - assertEquals(expectedDateValues, actualDateValues); - } - - /** - * Test number of dates in list after und of App. A correct run should deliver 20 date values - */ - @Test - public void testCounterDateValues() { - assertEquals(expectedCounterDateValues, actualCounterDateValues); - } - - /** - * Test number of Exceptions in list after und of App. A correct run should deliver no exceptions - */ - @Test - public void testCounterExceptions() { - assertEquals(expectedCounterExceptions, actualCounterExceptions); - } -} From 6202f3ab44700355f4bb7862ecaa74dd90acee33 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 11:42:16 +0100 Subject: [PATCH 31/40] Add files via upload --- .../test/java/com/iluwatar/tls/AppTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/AppTest.java diff --git a/tls/src/test/java/com/iluwatar/tls/AppTest.java b/tls/src/test/java/com/iluwatar/tls/AppTest.java new file mode 100644 index 000000000..073c0988a --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/AppTest.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import org.junit.Test; + +/** + * Tests that thread local storage example runs without errors. + * + * @author Thomas Bauer, January 2017 + * + */ +public class AppTest { + @Test + public void test() throws Exception { + String[] args = {}; + App.main(args); + } +} From 3324e1bc432867766182c7bb743af938093aa81f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:01:32 +0100 Subject: [PATCH 32/40] Update pom.xml added tls --- pom.xml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 52f24a500..12b4c3a06 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0 com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT pom 2014 @@ -50,7 +50,8 @@ abstract-factory - builder + tls + builder factory-method prototype singleton @@ -466,4 +467,9 @@ - \ No newline at end of file + + + Contact GitHub API Training Shop Blog About + + © 2017 GitHub, Inc. Terms Privacy Security Status Help + From 3d3dd58501e0911a4e431d4e9ab2a22b5777c6fe Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:08:11 +0100 Subject: [PATCH 33/40] Update pom.xml removed errors caused by copy code from master --- pom.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 12b4c3a06..42ae2626c 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ abstract-factory tls - builder + builder factory-method prototype singleton @@ -468,8 +468,3 @@ - - Contact GitHub API Training Shop Blog About - - © 2017 GitHub, Inc. Terms Privacy Security Status Help - From 59ea20745f468819894a440a42a0a76383225151 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:32:21 +0100 Subject: [PATCH 34/40] Delete DateFormatRunnableTest.java --- .../iluwatar/tls/DateFormatRunnableTest.java | 144 ------------------ 1 file changed, 144 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java deleted file mode 100644 index d6105dc98..000000000 --- a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * - * Test of the Callable - * - * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) - *

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

- * Additionally the number of list entries are tested for both the list with the date values - * and the list with the exceptions - * - * @author Thomas Bauer, January 2017 - * - */ -public class DateFormatRunnableTest { - - // Class variables used in setup() have to be static because setup() has to be static - /** - * Result object given back by DateFormatCallable - * -- Array with converted date values - * -- Array with thrown exceptions - */ - static Result result; - - /** - * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method - */ - static List createdDateValues = new ArrayList(); - - /** - * Expected number of date values in the date value list created by the run of DateFormatRunnalbe - */ - int expectedCounterDateValues = 5; - - /** - * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. - */ - int expectedCounterExceptions = 0; - - /** - * Expected content of the list containing the date values created by the run of DateFormatRunnalbe - */ - List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); - - /** - * Run Callable and prepare results for usage in the test methods - */ - @BeforeClass - public static void setup() { - // Create a callable - DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); - // start thread using the Callable instance - ExecutorService executor = Executors.newCachedThreadPool(); - Future futureResult = executor.submit(callableDf); - try { - result = futureResult.get(); - createdDateValues = convertDatesToString(result); - } catch (Exception e) { - fail("Setup failed: " + e); - } - executor.shutdown(); - } - - private static List convertDatesToString(Result res) { - // Format date value as DD.MM.YYYY - if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { - return null; - } - List returnList = new ArrayList(); - - for (Date dt : res.getDateList()) { - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); - } - return returnList; - } - - /** - * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 - */ - @Test - public void testDateValues() { - assertEquals(expectedDateValues, createdDateValues); - } - - /** - * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver 5 date values - */ - @Test - public void testCounterDateValues() { - assertEquals(expectedCounterDateValues, result.getDateList().size()); - } - - /** - * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should deliver - * no exceptions - */ - @Test - public void testCounterExceptions() { - assertEquals(expectedCounterExceptions, result.getExceptionList().size()); - } -} From 82f8460243e49d7bd5804acf3b1f1331284cc66c Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:32:32 +0100 Subject: [PATCH 35/40] Delete DateFormatRunnableTestIncorrectDateFormat.java --- ...FormatRunnableTestIncorrectDateFormat.java | 127 ------------------ 1 file changed, 127 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java deleted file mode 100644 index bae89f160..000000000 --- a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestIncorrectDateFormat.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * - * Test of the Callable - * - * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) - *

- * An incorrect formatted date is passed to the Callable - * After a successful run 0 date values and 5 exceptions should be in the result object. - * - * @author Thomas Bauer, January 2017 - * - */ -public class DateFormatRunnableTestIncorrectDateFormat { - - // Class variables used in setup() have to be static because setup() has to be static - /** - * Result object given back by DateFormatCallable - * -- Array with converted date values - * -- Array with thrown exceptions - */ - static Result result; - - /** - * The date values created by the run of DateFormatRunnalbe. List will be filled in the setup() method - */ - static List createdExceptions = new ArrayList(); - - /** - * Expected number of date values in the date value list created by the run of DateFormatRunnalbe - */ - int expectedCounterDateValues = 0; - - /** - * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. - */ - int expectedCounterExceptions = 5; - - /** - * Expected content of the list containing the exceptions created by the run of DateFormatRunnalbe - */ - List expectedExceptions = Arrays.asList("class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\"", - "class java.text.ParseException: Unparseable date: \"15.12.2015\""); - - /** - * Run Callable and prepare results for usage in the test methods - */ - @BeforeClass - public static void setup() { - // Create a callable. Pass a string date value not matching the format string - DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15.12.2015"); - // start thread using the Callable instance - ExecutorService executor = Executors.newCachedThreadPool(); - Future futureResult = executor.submit(callableDf); - try { - result = futureResult.get(); - } catch (Exception e) { - fail("Setup failed: " + e); - } - executor.shutdown(); - } - - /** - * Test Exceptions after the run of DateFormatRunnalbe. A correct run should deliver 5 times the - * same exception - */ - @Test - public void testExecptions() { - assertEquals(expectedExceptions, result.getExceptionList()); - } - - /** - * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver no date values - */ - @Test - public void testCounterDateValues() { - assertEquals(expectedCounterDateValues, result.getDateList().size()); - } - - /** - * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should - * deliver 5 exceptions - */ - @Test - public void testCounterExceptions() { - assertEquals(expectedCounterExceptions, result.getExceptionList().size()); - } -} From 2bbf84233e9c4d04e1c4fbe538f07d996f702458 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:32:44 +0100 Subject: [PATCH 36/40] Delete DateFormatRunnableTestMultiThread.java --- .../DateFormatRunnableTestMultiThread.java | 164 ------------------ 1 file changed, 164 deletions(-) delete mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java b/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java deleted file mode 100644 index 354915209..000000000 --- a/tls/src/test/java/com/iluwatar/tls/DateFormatRunnableTestMultiThread.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * The MIT License - * Copyright (c) 2016 Thomas Bauer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.iluwatar.tls; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * - * Test of the Callable - * - * In this test {@link DateFormatCallable} is used by 4 threads in parallel - *

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

- * Additionally the number of list entries are tested for both the list with the date values - * and the list with the exceptions - * - * @author Thomas Bauer, January 2017 - * - */ -public class DateFormatRunnableTestMultiThread { - - // Class variables used in setup() have to be static because setup() has to be static - /** - * Result object given back by DateFormatCallable, one for each thread - * -- Array with converted date values - * -- Array with thrown exceptions - */ - static Result[] result = new Result[4]; - - /** - * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method - */ - @SuppressWarnings("serial") - static class StringArrayList extends ArrayList { - /* nothing needed here */ - } - static List[] createdDateValues = new StringArrayList[4]; - - /** - * Expected number of date values in the date value list created by each thread - */ - int expectedCounterDateValues = 5; - - /** - * Expected number of exceptions in the exception list created by each thread - */ - int expectedCounterExceptions = 0; - - /** - * Expected content of the list containing the date values created by each thread - */ - List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); - - /** - * Run Callable and prepare results for usage in the test methods - */ - @BeforeClass - public static void setup() { - // Create a callable - DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); - // start thread using the Callable instance - ExecutorService executor = Executors.newCachedThreadPool(); - Future futureResult1 = executor.submit(callableDf); - Future futureResult2 = executor.submit(callableDf); - Future futureResult3 = executor.submit(callableDf); - Future futureResult4 = executor.submit(callableDf); - try { - result[0] = futureResult1.get(); - result[1] = futureResult2.get(); - result[2] = futureResult3.get(); - result[3] = futureResult4.get(); - for (int i = 0; i < result.length; i++) { - createdDateValues[i] = convertDatesToString(result[i]); - } - } catch (Exception e) { - fail("Setup failed: " + e); - } - executor.shutdown(); - } - - private static List convertDatesToString(Result res) { - // Format date value as DD.MM.YYYY - if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { - return null; - } - List returnList = new StringArrayList(); - - for (Date dt : res.getDateList()) { - Calendar cal = Calendar.getInstance(); - cal.setTime(dt); - returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); - } - return returnList; - } - - /** - * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 - * by each thread - */ - @Test - public void testDateValues() { - for (int i = 0; i < createdDateValues.length; i++) { - assertEquals(expectedDateValues, createdDateValues[i]); - } - } - - /** - * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should - * deliver 5 date values by each thread - */ - @Test - public void testCounterDateValues() { - for (int i = 0; i < result.length; i++) { - assertEquals(expectedCounterDateValues, result[i].getDateList().size()); - } - } - - /** - * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should - * deliver no exceptions - */ - @Test - public void testCounterExceptions() { - for (int i = 0; i < result.length; i++) { - assertEquals(expectedCounterExceptions, result[i].getExceptionList().size()); - } - } -} From ddac9dc6cb09a314111aed660c98c5b1fa12a9ce Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 29 Jan 2017 12:34:13 +0100 Subject: [PATCH 37/40] Add files via upload Changed the classname part "runnable" to "callable" --- .../iluwatar/tls/DateFormatCallableTest.java | 144 +++++++++++++++ ...FormatCallableTestIncorrectDateFormat.java | 127 ++++++++++++++ .../DateFormatCallableTestMultiThread.java | 164 ++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java create mode 100644 tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java new file mode 100644 index 000000000..b4f24be9b --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTest.java @@ -0,0 +1,144 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

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

+ * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatCallableTest { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdDateValues = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by the run of DateFormatRunnalbe + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + createdDateValues = convertDatesToString(result); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new ArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + */ + @Test + public void testDateValues() { + assertEquals(expectedDateValues, createdDateValues); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver 5 date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should deliver + * no exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java new file mode 100644 index 000000000..e0a1507e9 --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestIncorrectDateFormat.java @@ -0,0 +1,127 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is tested with only one thread (i.e. without concurrency situation) + *

+ * An incorrect formatted date is passed to the Callable + * After a successful run 0 date values and 5 exceptions should be in the result object. + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatCallableTestIncorrectDateFormat { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result result; + + /** + * The date values created by the run of DateFormatRunnalbe. List will be filled in the setup() method + */ + static List createdExceptions = new ArrayList(); + + /** + * Expected number of date values in the date value list created by the run of DateFormatRunnalbe + */ + int expectedCounterDateValues = 0; + + /** + * Expected number of exceptions in the exception list created by the run of DateFormatRunnalbe. + */ + int expectedCounterExceptions = 5; + + /** + * Expected content of the list containing the exceptions created by the run of DateFormatRunnalbe + */ + List expectedExceptions = Arrays.asList("class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\"", + "class java.text.ParseException: Unparseable date: \"15.12.2015\""); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable. Pass a string date value not matching the format string + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15.12.2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult = executor.submit(callableDf); + try { + result = futureResult.get(); + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + /** + * Test Exceptions after the run of DateFormatRunnalbe. A correct run should deliver 5 times the + * same exception + */ + @Test + public void testExecptions() { + assertEquals(expectedExceptions, result.getExceptionList()); + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should deliver no date values + */ + @Test + public void testCounterDateValues() { + assertEquals(expectedCounterDateValues, result.getDateList().size()); + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 exceptions + */ + @Test + public void testCounterExceptions() { + assertEquals(expectedCounterExceptions, result.getExceptionList().size()); + } +} diff --git a/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java new file mode 100644 index 000000000..635d6f25a --- /dev/null +++ b/tls/src/test/java/com/iluwatar/tls/DateFormatCallableTestMultiThread.java @@ -0,0 +1,164 @@ +/** + * The MIT License + * Copyright (c) 2016 Thomas Bauer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.tls; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * Test of the Callable + * + * In this test {@link DateFormatCallable} is used by 4 threads in parallel + *

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

+ * Additionally the number of list entries are tested for both the list with the date values + * and the list with the exceptions + * + * @author Thomas Bauer, January 2017 + * + */ +public class DateFormatCallableTestMultiThread { + + // Class variables used in setup() have to be static because setup() has to be static + /** + * Result object given back by DateFormatCallable, one for each thread + * -- Array with converted date values + * -- Array with thrown exceptions + */ + static Result[] result = new Result[4]; + + /** + * The date values created by the run of of DateFormatRunnalbe. List will be filled in the setup() method + */ + @SuppressWarnings("serial") + static class StringArrayList extends ArrayList { + /* nothing needed here */ + } + static List[] createdDateValues = new StringArrayList[4]; + + /** + * Expected number of date values in the date value list created by each thread + */ + int expectedCounterDateValues = 5; + + /** + * Expected number of exceptions in the exception list created by each thread + */ + int expectedCounterExceptions = 0; + + /** + * Expected content of the list containing the date values created by each thread + */ + List expectedDateValues = Arrays.asList("15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015", "15.11.2015"); + + /** + * Run Callable and prepare results for usage in the test methods + */ + @BeforeClass + public static void setup() { + // Create a callable + DateFormatCallable callableDf = new DateFormatCallable("dd/MM/yyyy", "15/12/2015"); + // start thread using the Callable instance + ExecutorService executor = Executors.newCachedThreadPool(); + Future futureResult1 = executor.submit(callableDf); + Future futureResult2 = executor.submit(callableDf); + Future futureResult3 = executor.submit(callableDf); + Future futureResult4 = executor.submit(callableDf); + try { + result[0] = futureResult1.get(); + result[1] = futureResult2.get(); + result[2] = futureResult3.get(); + result[3] = futureResult4.get(); + for (int i = 0; i < result.length; i++) { + createdDateValues[i] = convertDatesToString(result[i]); + } + } catch (Exception e) { + fail("Setup failed: " + e); + } + executor.shutdown(); + } + + private static List convertDatesToString(Result res) { + // Format date value as DD.MM.YYYY + if (res == null || res.getDateList() == null || res.getDateList().size() == 0) { + return null; + } + List returnList = new StringArrayList(); + + for (Date dt : res.getDateList()) { + Calendar cal = Calendar.getInstance(); + cal.setTime(dt); + returnList.add(cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR)); + } + return returnList; + } + + /** + * Test date values after the run of DateFormatRunnalbe. A correct run should deliver 5 times 15.12.2015 + * by each thread + */ + @Test + public void testDateValues() { + for (int i = 0; i < createdDateValues.length; i++) { + assertEquals(expectedDateValues, createdDateValues[i]); + } + } + + /** + * Test number of dates in the list after the run of DateFormatRunnalbe. A correct run should + * deliver 5 date values by each thread + */ + @Test + public void testCounterDateValues() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterDateValues, result[i].getDateList().size()); + } + } + + /** + * Test number of Exceptions in the list after the run of DateFormatRunnalbe. A correct run should + * deliver no exceptions + */ + @Test + public void testCounterExceptions() { + for (int i = 0; i < result.length; i++) { + assertEquals(expectedCounterExceptions, result[i].getExceptionList().size()); + } + } +} From fd7107694a75ebe7cadee666e3d397ed468df86f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Feb 2017 15:16:15 +0100 Subject: [PATCH 38/40] Update pom.xml Changed 1.14.0-SNAPSHOT to 1.15.0-SNAPSHOT --- tls/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tls/pom.xml b/tls/pom.xml index 68ebcdbf1..fa8bf6860 100644 --- a/tls/pom.xml +++ b/tls/pom.xml @@ -30,7 +30,7 @@ com.iluwatar java-design-patterns - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT tls From 2c2d874ac89fdceda239e55ac26ce1470a543aae Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Mar 2017 10:00:13 +0100 Subject: [PATCH 39/40] Update App.java Correction of error detected by maven-pmd-plugin. --- tls/src/main/java/com/iluwatar/tls/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java index 80e87042c..bc67d0c2c 100644 --- a/tls/src/main/java/com/iluwatar/tls/App.java +++ b/tls/src/main/java/com/iluwatar/tls/App.java @@ -104,7 +104,7 @@ public class App { System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); } catch (Exception e) { - // no action here + System.out.println("Abnormal end of program. Program throws exception: "); } executor.shutdown(); } From f84c4c161120fa18ae2a1c854e61229df23b9aef Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Mar 2017 10:02:37 +0100 Subject: [PATCH 40/40] Update App.java Correction of correction ;-) --- tls/src/main/java/com/iluwatar/tls/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tls/src/main/java/com/iluwatar/tls/App.java b/tls/src/main/java/com/iluwatar/tls/App.java index bc67d0c2c..634d36d26 100644 --- a/tls/src/main/java/com/iluwatar/tls/App.java +++ b/tls/src/main/java/com/iluwatar/tls/App.java @@ -104,7 +104,7 @@ public class App { System.out.println("The List exceptionList contains " + counterExceptions + " exceptions"); } catch (Exception e) { - System.out.println("Abnormal end of program. Program throws exception: "); + System.out.println("Abnormal end of program. Program throws exception: " + e); } executor.shutdown(); }