From a90569a5e838c267a7f40015731c0a015482d23c Mon Sep 17 00:00:00 2001 From: Patrick Guillerm Date: Sun, 25 Mar 2018 14:32:41 +0200 Subject: [PATCH 1/5] PGU - add tests with subs threads --- ...sult.java => CallableWithErrorResult.java} | 10 ++- .../services/threads/RunAndCloseService.java | 34 ++++++--- .../threads/TimeoutTaskException.java | 41 +++++++++++ .../api/services/threads/ComplexTask.java | 72 +++++++++++++++++++ .../threads/RunAndCloseServiceTest.java | 33 +++++++-- .../api/services/threads/SimpleTask.java | 21 ++++-- 6 files changed, 192 insertions(+), 19 deletions(-) rename monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/{CallableTimeoutResult.java => CallableWithErrorResult.java} (58%) create mode 100644 monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/TimeoutTaskException.java create mode 100644 monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java diff --git a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/CallableTimeoutResult.java b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/CallableWithErrorResult.java similarity index 58% rename from monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/CallableTimeoutResult.java rename to monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/CallableWithErrorResult.java index 6dd1075..ac20c04 100644 --- a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/CallableTimeoutResult.java +++ b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/CallableWithErrorResult.java @@ -14,6 +14,12 @@ * @author patrickguillerm * @since 24 mars 2018 */ -public interface CallableTimeoutResult extends Callable { - V getTimeoutResult(); +public interface CallableWithErrorResult extends Callable { + default V getTimeoutResult() { + return null; + } + + default V getErrorResult(Exception error) { + return null; + } } diff --git a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java index b1b7e65..9a58111 100644 --- a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java +++ b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java @@ -8,7 +8,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -89,7 +88,7 @@ public RunAndCloseService(final String threadsName, final long timeout, final in int howManyThreads = tasks.size() < nbThreads ? tasks.size() : nbThreads; this.threadsName = threadsName; this.timeout = timeout; - this.onError = onError == null ? this::handlerError : onError; + this.onError = onError; tasksAndFutures = new HashMap<>(); threadGroup = Thread.currentThread().getThreadGroup(); executor = Executors.newFixedThreadPool(howManyThreads, this); @@ -163,16 +162,12 @@ public Thread newThread(Runnable runnable) { // ========================================================================= // ERRORS // ========================================================================= - private T handlerError(Exception error, Callable task) { - Loggers.DEBUGLOG.error(error.getMessage(), error); - return null; - } - private List handlerTimeoutTask() { List result = new ArrayList<>(); for (Map.Entry, Callable> entry : tasksAndFutures.entrySet()) { if (!entry.getKey().isDone()) { - T taskData = onError.apply(new TimeoutException(), entry.getValue()); + final Callable task = entry.getValue(); + T taskData = processHandlerError(null, task); if (taskData != null) { result.add(taskData); } @@ -181,6 +176,29 @@ private List handlerTimeoutTask() { return result; } + private T processHandlerError(Exception error, Callable task) { + T result = null; + if (onError == null) { + result = handlerError(error, task); + } else { + result = onError.apply(error, task); + } + return result; + } + + private T handlerError(Exception error, Callable task) { + T result = null; + if (task instanceof CallableWithErrorResult) { + if (error == null) { + result = ((CallableWithErrorResult) task).getTimeoutResult(); + } else { + result = ((CallableWithErrorResult) task).getErrorResult(error); + } + } + + return result; + } + private Callable resolveTask(Future itemFuture) { // TODO Auto-generated method stub return null; diff --git a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/TimeoutTaskException.java b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/TimeoutTaskException.java new file mode 100644 index 0000000..700c611 --- /dev/null +++ b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/TimeoutTaskException.java @@ -0,0 +1,41 @@ +/* WIEDZA + * ----------------- + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + */ +package org.wiedza.monitoring.api.services.threads; + +/** + * TimeoutTaskException + * + * @author patrickguillerm + * @since 25 mars 2018 + */ +public class TimeoutTaskException extends Exception { + + // ========================================================================= + // ATTRIBUTES + // ========================================================================= + private static final long serialVersionUID = 4991745549592164932L; + + // ========================================================================= + // CONSTRUCTORS + // ========================================================================= + + public TimeoutTaskException() { + super(); + } + + public TimeoutTaskException(String message, Throwable cause) { + super(message, cause); + } + + public TimeoutTaskException(String message) { + super(message); + } + + public TimeoutTaskException(Throwable cause) { + super(cause); + } +} diff --git a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java new file mode 100644 index 0000000..c449a1a --- /dev/null +++ b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java @@ -0,0 +1,72 @@ +/* WIEDZA + * ----------------- + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + */ +package org.wiedza.monitoring.api.services.threads; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * ComplexTask + * + * @author patrickguillerm + * @since 25 mars 2018 + */ +public class ComplexTask implements CallableWithErrorResult { + + // ========================================================================= + // ATTRIBUTES + // ========================================================================= + private final String value; + + // ========================================================================= + // METHODS + // ========================================================================= + public ComplexTask(String value) { + this.value = value; + } + + // ========================================================================= + // OVERRIDES + // ========================================================================= + @Override + public String call() throws Exception { + List> tasks = buildTask(); + //@formatter:off + List data = new RunAndCloseService<>("test" + value, + 1500L, + 2, + tasks).run(); + //@formatter:on + return String.join(" | ", data); + } + + private List> buildTask() { + final List> result = new ArrayList<>(); + + if ("1".equals(value)) { + result.add(new SimpleTask(500, "1.1")); + result.add(new SimpleTask(400, "1.2")); + result.add(new SimpleTask(1000, "1.3")); + result.add(new SimpleTask(500, "1.4", false)); + } else { + result.add(new SimpleTask(100, value + ".1")); + result.add(new SimpleTask(500, value + ".2")); + result.add(new SimpleTask(2000, value + ".3")); + result.add(new SimpleTask(100, value + ".4")); + } + return result; + } + + // ========================================================================= + // GETTERS & SETTERS + // ========================================================================= + @Override + public String getTimeoutResult() { + return "null"; + } +} diff --git a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java index 7075384..1d5fcd7 100644 --- a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java +++ b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java @@ -40,6 +40,7 @@ public class RunAndCloseServiceTest { // ========================================================================= @Test public void testWithoutTimeout() { + LOGGER.info("========== testWithoutTimeout =========="); //@formatter:off Chrono chrono = Chrono.startChrono(); List data = new RunAndCloseService<>("test", @@ -60,6 +61,7 @@ public void testWithoutTimeout() { @Test public void testWithTimeout() { + LOGGER.info("========== testWithTimeout =========="); //@formatter:off Chrono chrono = Chrono.startChrono(); List data = new RunAndCloseService<>("test", @@ -76,16 +78,16 @@ public void testWithTimeout() { assertTrue(chrono.getDuration() >= 2000L); assertTrue(chrono.getDuration() < 2050L); data.forEach(m -> LOGGER.info("number : {}", m)); - assertListEquals(data, "1", "3"); + assertListEquals(data, "1", "3", "timeout - 4", "timeout - 2"); } @Test public void testWithTimeoutAndErrorHandler() { - + LOGGER.info("========== testWithTimeoutAndErrorHandler =========="); BiFunction, String> onError = (error, task) -> { String result = "null"; - if (task instanceof CallableTimeoutResult) { - result = ((CallableTimeoutResult) task).getTimeoutResult(); + if (task instanceof CallableWithErrorResult) { + result = ((CallableWithErrorResult) task).getTimeoutResult(); } return result; }; @@ -103,12 +105,33 @@ public void testWithTimeoutAndErrorHandler() { //@formatter:on chrono.stop(); LOGGER.info("duration : {}", chrono.getDuration()); - assertTrue(chrono.getDuration() > 2000L); + assertTrue(chrono.getDuration() >= 2000L); assertTrue(chrono.getDuration() < 2050L); data.forEach(m -> LOGGER.info("number : {}", m)); assertListEquals(data, "1", "3", "timeout - 2", "timeout - 4"); } + @Test + public void testWithSubTask() { + LOGGER.info("========== testWithSubTask =========="); + //@formatter:off + Chrono chrono = Chrono.startChrono(); + List data = new RunAndCloseService<>("test", + 2000L, + 2, + new ComplexTask("1"), + new ComplexTask("2") + ).run(); + //@formatter:on + chrono.stop(); + LOGGER.info("duration : {}", chrono.getDuration()); + data.forEach(m -> LOGGER.info("number : {}", m)); + //@formatter:off + assertListEquals(data, "1.2 | 1.1 | 1.4 | 1.3", + "2.1 | 2.2 | 2.4 | timeout - 2.3"); + //@formatter:on + } + // ========================================================================= // TOOLS // ========================================================================= diff --git a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/SimpleTask.java b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/SimpleTask.java index 2f7ad6f..09618bb 100644 --- a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/SimpleTask.java +++ b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/SimpleTask.java @@ -12,22 +12,29 @@ * @author patrickguillerm * @since 24 mars 2018 */ -public class SimpleTask implements CallableTimeoutResult { +public class SimpleTask implements CallableWithErrorResult { // ========================================================================= // ATTRIBUTES // ========================================================================= - private final int sleepTime; + private final int sleepTime; - private final String result; + private final String result; + + private final boolean error; // ========================================================================= // CONSTRUCTORS // ========================================================================= public SimpleTask(int sleepTime, String result) { - super(); + this(sleepTime, result, false); + + } + + public SimpleTask(int sleepTime, String result, boolean error) { this.sleepTime = sleepTime; this.result = result; + this.error = error; } // ========================================================================= @@ -36,6 +43,9 @@ public SimpleTask(int sleepTime, String result) { @Override public String call() throws Exception { Thread.sleep(sleepTime); + if (error) { + throw new Exception("Error occurs!"); + } return result; } @@ -43,4 +53,7 @@ public String getTimeoutResult() { return "timeout - " + result; } + public String getErrorResult(Exception error) { + return "error - " + result; + } } From 439ad3a86b900bd5df4332b55d741760b36dcb50 Mon Sep 17 00:00:00 2001 From: Patrick Guillerm Date: Sun, 25 Mar 2018 21:16:11 +0200 Subject: [PATCH 2/5] PGU - manage potential error from Callables --- .../services/threads/RunAndCloseService.java | 44 ++++++++++++++----- .../api/services/threads/ComplexTask.java | 2 +- .../threads/RunAndCloseServiceTest.java | 26 +++++++---- 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java index 9a58111..709a3ca 100644 --- a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java +++ b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java @@ -20,12 +20,12 @@ import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.wiedza.monitoring.api.exceptions.Asserts; -import org.wiedza.monitoring.api.loggers.Loggers; import org.wiedza.monitoring.api.time.Chrono; /** @@ -39,6 +39,8 @@ public class RunAndCloseService implements ThreadFactory { // ========================================================================= // ATTRIBUTES // ========================================================================= + private static final Logger LOGGER = LoggerFactory.getLogger(RunAndCloseService.class); + private final String threadsName; private final List> tasks; @@ -115,8 +117,6 @@ public List run() { tasksLeft = tasksLeft - 1; } } catch (ExecutionException | InterruptedException error) { - Callable task = resolveTask(itemFuture); - taskData = handlerError(error, task); tasksLeft = tasksLeft - 1; } @@ -141,15 +141,40 @@ private long computeTimeLeft(long timeLeft, final Chrono chrono) { private List> sumitTask() { final List> result = new ArrayList<>(); for (Callable task : tasks) { - final Future future = completion.submit(task); + final Future future = completion.submit(new CallableTask(task, this)); result.add(future); tasksAndFutures.put(future, task); } return result; } + private class CallableTask implements Callable { + private final Callable task; + + private final RunAndCloseService runAndCloseService; + + public CallableTask(Callable task, RunAndCloseService runAndCloseService) { + this.task = task; + this.runAndCloseService = runAndCloseService; + } + + @Override + public U call() throws Exception { + U result = null; + try { + result = task.call(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + result = runAndCloseService.processHandlerError(e, task); + } + + return result; + } + + } + // ========================================================================= - // OVERRIDES + // new Thread // ========================================================================= @Override public Thread newThread(Runnable runnable) { @@ -176,7 +201,7 @@ private List handlerTimeoutTask() { return result; } - private T processHandlerError(Exception error, Callable task) { + private synchronized T processHandlerError(Exception error, Callable task) { T result = null; if (onError == null) { result = handlerError(error, task); @@ -199,9 +224,4 @@ private T handlerError(Exception error, Callable task) { return result; } - private Callable resolveTask(Future itemFuture) { - // TODO Auto-generated method stub - return null; - } - } diff --git a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java index c449a1a..f4898be 100644 --- a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java +++ b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/ComplexTask.java @@ -52,7 +52,7 @@ private List> buildTask() { result.add(new SimpleTask(500, "1.1")); result.add(new SimpleTask(400, "1.2")); result.add(new SimpleTask(1000, "1.3")); - result.add(new SimpleTask(500, "1.4", false)); + result.add(new SimpleTask(500, "1.4", true)); } else { result.add(new SimpleTask(100, value + ".1")); result.add(new SimpleTask(500, value + ".2")); diff --git a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java index 1d5fcd7..2dea2a5 100644 --- a/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java +++ b/monitoring-api/src/test/java/org/wiedza/monitoring/api/services/threads/RunAndCloseServiceTest.java @@ -31,9 +31,6 @@ public class RunAndCloseServiceTest { // ATTRIBUTES // ========================================================================= private static final Logger LOGGER = LoggerFactory.getLogger(RunAndCloseServiceTest.class.getSimpleName()); - // ========================================================================= - // CONSTRUCTORS - // ========================================================================= // ========================================================================= // METHODS @@ -70,7 +67,7 @@ public void testWithTimeout() { new SimpleTask(500,"1"), new SimpleTask(10000,"2"), new SimpleTask(1000,"3"), - new SimpleTask(700,"4") + new SimpleTask(600,"4") ).run(); //@formatter:on chrono.stop(); @@ -78,7 +75,14 @@ public void testWithTimeout() { assertTrue(chrono.getDuration() >= 2000L); assertTrue(chrono.getDuration() < 2050L); data.forEach(m -> LOGGER.info("number : {}", m)); - assertListEquals(data, "1", "3", "timeout - 4", "timeout - 2"); + + assertEquals("1", data.get(0)); + assertEquals("3", data.get(1)); + if ("timeout - 2".equals(data.get(2))) { + assertEquals("timeout - 4", data.get(3)); + } else { + assertEquals("timeout - 2", data.get(3)); + } } @Test @@ -108,7 +112,13 @@ public void testWithTimeoutAndErrorHandler() { assertTrue(chrono.getDuration() >= 2000L); assertTrue(chrono.getDuration() < 2050L); data.forEach(m -> LOGGER.info("number : {}", m)); - assertListEquals(data, "1", "3", "timeout - 2", "timeout - 4"); + assertEquals("1", data.get(0)); + assertEquals("3", data.get(1)); + if ("timeout - 2".equals(data.get(2))) { + assertEquals("timeout - 4", data.get(3)); + } else { + assertEquals("timeout - 2", data.get(3)); + } } @Test @@ -127,7 +137,7 @@ public void testWithSubTask() { LOGGER.info("duration : {}", chrono.getDuration()); data.forEach(m -> LOGGER.info("number : {}", m)); //@formatter:off - assertListEquals(data, "1.2 | 1.1 | 1.4 | 1.3", + assertListEquals(data, "1.2 | 1.1 | error - 1.4 | 1.3", "2.1 | 2.2 | 2.4 | timeout - 2.3"); //@formatter:on } @@ -139,7 +149,7 @@ private void assertListEquals(List data, String... ref) { assertNotNull(data); assertEquals(data.size(), ref.length); for (int i = 0; i < ref.length; i++) { - assertEquals(data.get(i), ref[i]); + assertEquals(ref[i], data.get(i)); } } From acaaf29e66a5ac149249422961c86937a12a3611 Mon Sep 17 00:00:00 2001 From: Patrick Guillerm Date: Sun, 25 Mar 2018 21:23:26 +0200 Subject: [PATCH 3/5] PGU - sonar --- .../java/org/wiedza/monitoring/api/loggers/Loggers.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java b/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java index 2db5d38..ef01c59 100644 --- a/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java +++ b/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java @@ -17,6 +17,12 @@ */ public final class Loggers { + // ========================================================================= + // CONSTRUCTOR + // ========================================================================= + private Loggers() { + } + // ========================================================================= // ATTRIBUTES // ========================================================================= From 89edbf443bff1809b9d81f8354e062840575b43a Mon Sep 17 00:00:00 2001 From: Patrick Guillerm Date: Sun, 25 Mar 2018 21:24:24 +0200 Subject: [PATCH 4/5] PGU - sonar --- .../monitoring/api/loggers/Loggers.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java b/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java index ef01c59..d5b6cb2 100644 --- a/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java +++ b/monitoring-api/src/main/java/org/wiedza/monitoring/api/loggers/Loggers.java @@ -26,24 +26,24 @@ private Loggers() { // ========================================================================= // ATTRIBUTES // ========================================================================= - public final static Logger XLLOG = LoggerFactory.getLogger("XLLOG"); + public static final Logger XLLOG = LoggerFactory.getLogger("XLLOG"); - public final static Logger DEBUGLOG = LoggerFactory.getLogger("DEBUGLOG"); + public static final Logger DEBUGLOG = LoggerFactory.getLogger("DEBUGLOG"); - public final static Logger SYSTEMLOG = LoggerFactory.getLogger("SYSTEMLOG"); + public static final Logger SYSTEMLOG = LoggerFactory.getLogger("SYSTEMLOG"); - public final static Logger AUDITOUTLINE = LoggerFactory.getLogger("AUDITOUTLINE"); + public static final Logger AUDITOUTLINE = LoggerFactory.getLogger("AUDITOUTLINE"); - public final static Logger IOLOG = LoggerFactory.getLogger("IOLOG"); + public static final Logger IOLOG = LoggerFactory.getLogger("IOLOG"); - public final static Logger PARTNERLOG = LoggerFactory.getLogger("PARTNERLOG"); + public static final Logger PARTNERLOG = LoggerFactory.getLogger("PARTNERLOG"); - public final static Logger SECURITY = LoggerFactory.getLogger("SECURITY"); + public static final Logger SECURITY = LoggerFactory.getLogger("SECURITY"); - public final static Logger SCRIPTS = LoggerFactory.getLogger("SCRIPTS"); + public static final Logger SCRIPTS = LoggerFactory.getLogger("SCRIPTS"); - public final static Logger BOOTSTRAP = LoggerFactory.getLogger("BOOTSTRAP"); + public static final Logger BOOTSTRAP = LoggerFactory.getLogger("BOOTSTRAP"); - public final static Logger CHRONOLOG = LoggerFactory.getLogger("CHRONOLOG"); + public static final Logger CHRONOLOG = LoggerFactory.getLogger("CHRONOLOG"); } From 162b9c68b996977276ceafb8002bcfb0ecd9bbd3 Mon Sep 17 00:00:00 2001 From: Patrick Guillerm Date: Sun, 25 Mar 2018 21:26:01 +0200 Subject: [PATCH 5/5] PGU - sonar --- .../monitoring/api/services/threads/RunAndCloseService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java index 709a3ca..6fa6ddb 100644 --- a/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java +++ b/monitoring-api/src/main/java/org/wiedza/monitoring/api/services/threads/RunAndCloseService.java @@ -94,7 +94,7 @@ public RunAndCloseService(final String threadsName, final long timeout, final in tasksAndFutures = new HashMap<>(); threadGroup = Thread.currentThread().getThreadGroup(); executor = Executors.newFixedThreadPool(howManyThreads, this); - completion = new ExecutorCompletionService(executor); + completion = new ExecutorCompletionService<>(executor); } // =========================================================================