From b3d8edcc845b4f025d7ba32c14770c28ff60c389 Mon Sep 17 00:00:00 2001 From: brunobat Date: Thu, 29 Nov 2018 12:21:07 +0000 Subject: [PATCH 1/8] TOMEE-2301 - project creation Signed-off-by: brunobat --- examples/executor/pom.xml | 68 ++++++++++++++++ .../superbiz/executor/AsyncBookService.java | 77 +++++++++++++++++++ .../executor/AsyncBookServiceTest.java | 73 ++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 examples/executor/pom.xml create mode 100644 examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java create mode 100644 examples/executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java diff --git a/examples/executor/pom.xml b/examples/executor/pom.xml new file mode 100644 index 00000000000..08a6dd30911 --- /dev/null +++ b/examples/executor/pom.xml @@ -0,0 +1,68 @@ + + + + 4.0.0 + + org.superbiz + executor + 8.0.0-SNAPSHOT + jar + OpenEJB :: Examples :: Executor for concurrency utilities + + + UTF-8 + 8.0 + 4.12 + + + + + org.apache.tomee + javaee-api + ${javaee-api.version} + provided + + + + junit + junit + ${junit.version} + test + + + org.apache.tomee + arquillian-tomee-remote + ${pom.version} + test + + + org.jboss.arquillian.junit + arquillian-junit-container + 1.4.0.Final + test + + + org.jboss.arquillian.container + arquillian-container-test-api + 1.4.0.Final + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.1 + + 1.8 + 1.8 + + + + + + \ No newline at end of file diff --git a/examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java b/examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java new file mode 100644 index 00000000000..1f17189fc40 --- /dev/null +++ b/examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java @@ -0,0 +1,77 @@ +package org.superbiz.executor; + +import javax.annotation.Resource; +import javax.ejb.Asynchronous; +import javax.enterprise.concurrent.ManagedExecutorService; +import javax.enterprise.context.RequestScoped; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@RequestScoped +public class AsyncBookService { + + @Resource + private ManagedExecutorService executor; + + @Asynchronous + public Future serviceA() { + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new IOException("Simulated error")); + return future; + } + + @Asynchronous + public CompletableFuture serviceB() { + return CompletableFuture.supplyAsync(delayedSupplier(1, 100), executor) + .thenApply(i -> i + 1); + } + + @Asynchronous + public CompletableFuture serviceB() { + return CompletableFuture.supplyAsync(delayedWithExceptionSupplier(100, new RuntimeException("test")), executor); + } + + private Supplier delayedSupplier(final int value, + final int delayMs) { + return () -> { + try { + Thread.sleep(delayMs); + } catch (InterruptedException e) { + throw new RuntimeException("Problem while waiting"); + } + return value; + }; + } + + private CompletableFuture delayedWithExceptionSupplier(final int delayMs, + final Throwable t) { + final CompletableFuture future = new CompletableFuture<>(); + try { + Thread.sleep(delayMs); + future.completeExceptionally(t); + } catch (InterruptedException e) { + throw new RuntimeException("Problem while waiting"); + } + return future; + } + +} diff --git a/examples/executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java b/examples/executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java new file mode 100644 index 00000000000..e567da47afa --- /dev/null +++ b/examples/executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java @@ -0,0 +1,73 @@ +package org.superbiz.executor; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.inject.Inject; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@RunWith(Arquillian.class) +public class AsyncBookServiceTest { + + @Inject + private AsyncBookService service; + + @Deployment() + public static final WebArchive app() { + return ShrinkWrap.create(WebArchive.class, "example.war") + .addClasses(AsyncBookService.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Test + public void testServiceA() { + final Future future = service.serviceA(); + try { + future.get(200, TimeUnit.MILLISECONDS); + } catch (InterruptedException | TimeoutException e) { + fail("Unexpected exception" + e); + } catch (ExecutionException ioe) { + assertEquals("Simulated error", ioe.getCause().getMessage()); + } + } + + @Test + public void testServiceB() { + final CompletableFuture future = service.serviceB(); + try { + assertEquals(2, future.get(200, TimeUnit.MILLISECONDS).intValue()); + } catch (Exception e) { + fail("Unexpected exception" + e); + } + } + +} \ No newline at end of file From d0c7290916d85ec1e7c85d0647ebb0bb2f7467b8 Mon Sep 17 00:00:00 2001 From: brunobat Date: Thu, 29 Nov 2018 12:21:19 +0000 Subject: [PATCH 2/8] TOMEE-2301 - Creation on 3 test: normal path, timeout, ended with exception Signed-off-by: brunobat rename project Signed-off-by: brunobat perform first example Signed-off-by: brunobat Add example with exception handling and refactor Signed-off-by: brunobat --- .../{executor => concurrency-utils}/pom.xml | 4 +- .../org/superbiz/executor/ManagedService.java | 89 +++++++++++++++++++ .../executor/ManagedServiceTest.java} | 87 ++++++++++++------ .../superbiz/executor/AsyncBookService.java | 77 ---------------- examples/pom.xml | 1 + 5 files changed, 150 insertions(+), 108 deletions(-) rename examples/{executor => concurrency-utils}/pom.xml (95%) create mode 100644 examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java rename examples/{executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java => concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java} (54%) delete mode 100644 examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java diff --git a/examples/executor/pom.xml b/examples/concurrency-utils/pom.xml similarity index 95% rename from examples/executor/pom.xml rename to examples/concurrency-utils/pom.xml index 08a6dd30911..0e0fba60120 100644 --- a/examples/executor/pom.xml +++ b/examples/concurrency-utils/pom.xml @@ -6,10 +6,10 @@ 4.0.0 org.superbiz - executor + concurrency-utils 8.0.0-SNAPSHOT jar - OpenEJB :: Examples :: Executor for concurrency utilities + OpenEJB :: Examples :: Concurrency utilities example UTF-8 diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java new file mode 100644 index 00000000000..89c89fedbeb --- /dev/null +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java @@ -0,0 +1,89 @@ +package org.superbiz.executor; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import javax.annotation.Resource; +import javax.enterprise.concurrent.ManagedExecutorService; +import javax.enterprise.context.RequestScoped; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +import static java.util.Objects.nonNull; + + +@RequestScoped +public class ManagedService { + + @Resource + private ManagedExecutorService executor; + + /** + * Executes an opperation asynchronously, in a different thread provided by the {@link ManagedExecutorService}. + * The computation will carry on after the return of the method. + * + * @param value The demo data. + * @return A {@link CompletableFuture} that will return immediately. + */ + public CompletableFuture asyncTask(final int value) { + return CompletableFuture + .supplyAsync(delayedTask(value, 100, null), executor) // Execute asynchronously. + .thenApply(i -> i + 1); // After the return of the task, do something else with the result. + } + + /** + * Executes an opperation asynchronously, in a different thread provided by the {@link ManagedExecutorService}. + * The computation will carry on after the return of the method. + * + * @param value The demo data. + * @return A {@link CompletableFuture} that will return immediately. + */ + public CompletableFuture asyncTaskWithException(final int value) { + return CompletableFuture + .supplyAsync(delayedTask(value, 100, "Planned exception"), executor) // Execute asynchronously. + .thenApply(i -> i + 1); // After the return of the task, do something else with the result. + } + + /** + * Method to simulate an asynchronous task. Will add 1 to the value for each invocation. + * + * @param value The demo data. + * @param delayMs How long the task will take to complete. In ms. + * @param errorMessage Message for the exception simulating an execution problem + * @return + */ + private Supplier delayedTask(final int value, + final int delayMs, + final String errorMessage) { + return () -> { + if (nonNull(errorMessage)) { + System.out.println("Exception will be thrown"); + throw new RuntimeException(errorMessage); + } + + try { + // simulate long processing task + Thread.sleep(delayMs); + } catch (InterruptedException e) { + throw new RuntimeException("Problem while waiting"); + } + System.out.println("delayedTask complete"); + return value + 1; + }; + } + +} diff --git a/examples/executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java similarity index 54% rename from examples/executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java rename to examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java index e567da47afa..1dd6ff9f9ee 100644 --- a/examples/executor/src/test/java/org/superbiz/executor/AsyncBookServiceTest.java +++ b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java @@ -1,5 +1,22 @@ package org.superbiz.executor; +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ShrinkWrap; @@ -11,63 +28,75 @@ import javax.inject.Inject; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ @RunWith(Arquillian.class) -public class AsyncBookServiceTest { +public class ManagedServiceTest { @Inject - private AsyncBookService service; + private ManagedService managedService; @Deployment() public static final WebArchive app() { return ShrinkWrap.create(WebArchive.class, "example.war") - .addClasses(AsyncBookService.class) + .addClasses(ManagedService.class) .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); } + /** + * Happy path. Normal invocation. + */ @Test - public void testServiceA() { - final Future future = service.serviceA(); + public void managedInvocationTest() { + final CompletableFuture future = managedService.asyncTask(1); + System.out.println("You can do something else in the meantime and later get the future value"); try { - future.get(200, TimeUnit.MILLISECONDS); - } catch (InterruptedException | TimeoutException e) { + // To prevent hanged tasks, you should obtain the value of a future with a timeout. + assertEquals(3, future.get(200, TimeUnit.MILLISECONDS).intValue()); + } catch (Exception e) { fail("Unexpected exception" + e); - } catch (ExecutionException ioe) { - assertEquals("Simulated error", ioe.getCause().getMessage()); } } + /** + * Request timeout. The result will take at least 100ms and we want it after 10ms. + * + * @throws InterruptedException + * @throws ExecutionException + * @throws TimeoutException + */ + @Test(expected = TimeoutException.class) + public void managedInvocationTestWithTimeout() throws InterruptedException, ExecutionException, TimeoutException { + final CompletableFuture future = managedService.asyncTask(1); + future.get(10, TimeUnit.MILLISECONDS); + } + + /** + * The execution ended with an exception. + * Handle the exception apropriately. + * + * @throws InterruptedException + * @throws ExecutionException + * @throws TimeoutException + */ @Test - public void testServiceB() { - final CompletableFuture future = service.serviceB(); + public void managedInvocationTestWithException() { + final CompletableFuture future = managedService.asyncTaskWithException(1); + try { - assertEquals(2, future.get(200, TimeUnit.MILLISECONDS).intValue()); + future.get(200, TimeUnit.MILLISECONDS); + } catch (ExecutionException e) { + // the thrown RuntimeException will be wrapped around an ExecutionException + assertEquals("Planned exception", e.getCause().getMessage()); } catch (Exception e) { fail("Unexpected exception" + e); } + } } \ No newline at end of file diff --git a/examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java b/examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java deleted file mode 100644 index 1f17189fc40..00000000000 --- a/examples/executor/src/main/java/org/superbiz/executor/AsyncBookService.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.superbiz.executor; - -import javax.annotation.Resource; -import javax.ejb.Asynchronous; -import javax.enterprise.concurrent.ManagedExecutorService; -import javax.enterprise.context.RequestScoped; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; -import java.util.function.Supplier; - -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - *

- * http://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@RequestScoped -public class AsyncBookService { - - @Resource - private ManagedExecutorService executor; - - @Asynchronous - public Future serviceA() { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new IOException("Simulated error")); - return future; - } - - @Asynchronous - public CompletableFuture serviceB() { - return CompletableFuture.supplyAsync(delayedSupplier(1, 100), executor) - .thenApply(i -> i + 1); - } - - @Asynchronous - public CompletableFuture serviceB() { - return CompletableFuture.supplyAsync(delayedWithExceptionSupplier(100, new RuntimeException("test")), executor); - } - - private Supplier delayedSupplier(final int value, - final int delayMs) { - return () -> { - try { - Thread.sleep(delayMs); - } catch (InterruptedException e) { - throw new RuntimeException("Problem while waiting"); - } - return value; - }; - } - - private CompletableFuture delayedWithExceptionSupplier(final int delayMs, - final Throwable t) { - final CompletableFuture future = new CompletableFuture<>(); - try { - Thread.sleep(delayMs); - future.completeExceptionally(t); - } catch (InterruptedException e) { - throw new RuntimeException("Problem while waiting"); - } - return future; - } - -} diff --git a/examples/pom.xml b/examples/pom.xml index 9a195007dbe..2531aa7970f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -174,6 +174,7 @@ BROKEN, see TOMEE-2140 mp-metrics-counted mp-metrics-timed websocket-tls-basic-auth + concurrency-utils From de075f8d9d7c96f26f9684119b150e7f52eaa225 Mon Sep 17 00:00:00 2001 From: brunobat Date: Mon, 3 Dec 2018 16:16:12 +0000 Subject: [PATCH 3/8] TOMEE-2301 - improving javadoc and adding output messages to track the execution. Use TimeUnit Sleep. Signed-off-by: brunobat --- .../org/superbiz/executor/ManagedService.java | 27 ++++++++++--------- .../superbiz/executor/ManagedServiceTest.java | 14 +++++----- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java index 89c89fedbeb..eecbb46d198 100644 --- a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java @@ -21,6 +21,7 @@ import javax.enterprise.concurrent.ManagedExecutorService; import javax.enterprise.context.RequestScoped; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import static java.util.Objects.nonNull; @@ -40,8 +41,9 @@ public class ManagedService { * @return A {@link CompletableFuture} that will return immediately. */ public CompletableFuture asyncTask(final int value) { + System.out.println("Create asyncTask"); return CompletableFuture - .supplyAsync(delayedTask(value, 100, null), executor) // Execute asynchronously. + .supplyAsync(longTask(value, 100, null), executor) // Execute asynchronously. .thenApply(i -> i + 1); // After the return of the task, do something else with the result. } @@ -53,22 +55,23 @@ public CompletableFuture asyncTask(final int value) { * @return A {@link CompletableFuture} that will return immediately. */ public CompletableFuture asyncTaskWithException(final int value) { + System.out.println("Create asyncTaskWithException"); return CompletableFuture - .supplyAsync(delayedTask(value, 100, "Planned exception"), executor) // Execute asynchronously. + .supplyAsync(longTask(value, 100, "Planned exception"), executor) // Execute asynchronously. .thenApply(i -> i + 1); // After the return of the task, do something else with the result. } /** * Method to simulate an asynchronous task. Will add 1 to the value for each invocation. * - * @param value The demo data. - * @param delayMs How long the task will take to complete. In ms. - * @param errorMessage Message for the exception simulating an execution problem - * @return + * @param value The demo data. + * @param taskDurationMs How long the task will take to complete. In ms. + * @param errorMessage Message for the exception simulating an execution problem + * @return a {@link Supplier} function processing the new value */ - private Supplier delayedTask(final int value, - final int delayMs, - final String errorMessage) { + private Supplier longTask(final int value, + final int taskDurationMs, + final String errorMessage) { return () -> { if (nonNull(errorMessage)) { System.out.println("Exception will be thrown"); @@ -76,12 +79,12 @@ private Supplier delayedTask(final int value, } try { - // simulate long processing task - Thread.sleep(delayMs); + // Simulate a long processing task using TimeUnit to sleep. + TimeUnit.MILLISECONDS.sleep(taskDurationMs); } catch (InterruptedException e) { throw new RuntimeException("Problem while waiting"); } - System.out.println("delayedTask complete"); + System.out.println("longTask complete"); return value + 1; }; } diff --git a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java index 1dd6ff9f9ee..30b6f6fcedc 100644 --- a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java +++ b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java @@ -66,9 +66,9 @@ public void managedInvocationTest() { /** * Request timeout. The result will take at least 100ms and we want it after 10ms. * - * @throws InterruptedException - * @throws ExecutionException - * @throws TimeoutException + * @throws InterruptedException we don't expect it + * @throws ExecutionException we don't expect it + * @throws TimeoutException Expected exception */ @Test(expected = TimeoutException.class) public void managedInvocationTestWithTimeout() throws InterruptedException, ExecutionException, TimeoutException { @@ -78,11 +78,11 @@ public void managedInvocationTestWithTimeout() throws InterruptedException, Exec /** * The execution ended with an exception. - * Handle the exception apropriately. + * Handle the exception appropriately. * - * @throws InterruptedException - * @throws ExecutionException - * @throws TimeoutException + * @throws InterruptedException we don't expect it + * @throws ExecutionException Expected exception + * @throws TimeoutException we don't expect it */ @Test public void managedInvocationTestWithException() { From fe7bc8ff6e0cfd8110ef687ca46afedbbcaeb8cf Mon Sep 17 00:00:00 2001 From: brunobat Date: Mon, 3 Dec 2018 18:25:25 +0000 Subject: [PATCH 4/8] TOMEE-2301 - Start with scheduled executor part Signed-off-by: brunobat --- .../executor/ManagedScheduledService.java | 83 +++++++++++++++++++ .../executor/ManagedScheduledServiceTest.java | 59 +++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java create mode 100644 examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java new file mode 100644 index 00000000000..1032f51e75e --- /dev/null +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java @@ -0,0 +1,83 @@ +package org.superbiz.executor; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import javax.annotation.Resource; +import javax.enterprise.concurrent.ManagedScheduledExecutorService; +import javax.enterprise.context.RequestScoped; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import static java.util.Objects.nonNull; + + +@RequestScoped +public class ManagedScheduledService { + + @Resource + private ManagedScheduledExecutorService executor; + + public Future singleFixedDelayTask(final int value) { + System.out.println("longCallableTask scheduled"); + return executor.schedule(longCallableTask(value, 10, null), 100, TimeUnit.MILLISECONDS); + } + + public ScheduledFuture periodicFixedDelayTask(final int value) { + return executor.scheduleAtFixedRate(longRunnableTask(value, 10, null), 0, 100, TimeUnit.MILLISECONDS); + } + + private Runnable longRunnableTask(final int value, + final int taskDurationMs, + final String errorMessage) { + return () -> { + if (nonNull(errorMessage)) { + System.out.println("Exception will be thrown"); + throw new RuntimeException(errorMessage); + } + + Integer result = value + 1; + System.out.println("longRunnableTask complete. Value is " + result); + // Cannot return result with a Runnable. + }; + } + + private Callable longCallableTask(final int value, + final int taskDurationMs, + final String errorMessage) { + return () -> { + System.out.println("longCallableTask start"); + if (nonNull(errorMessage)) { + System.out.println("Exception will be thrown"); + throw new RuntimeException(errorMessage); + } + + try { + // Simulate a long processing task using TimeUnit to sleep. + TimeUnit.MILLISECONDS.sleep(taskDurationMs); + } catch (InterruptedException e) { + throw new RuntimeException("Problem while waiting"); + } + System.out.println("longCallableTask complete"); + // We can return a result with a Callable. + return value + 1; + }; + } + +} diff --git a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java new file mode 100644 index 00000000000..b4e3807538e --- /dev/null +++ b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java @@ -0,0 +1,59 @@ +package org.superbiz.executor; +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.inject.Inject; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.junit.Assert.assertEquals; + +@RunWith(Arquillian.class) +public class ManagedScheduledServiceTest { + + @Inject + private ManagedScheduledService scheduledService; + + @Deployment() + public static final WebArchive app() { + return ShrinkWrap.create(WebArchive.class, "example.war") + .addClasses(ManagedScheduledService.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + + @Test + public void singleFixedDelayTask() throws InterruptedException, ExecutionException, TimeoutException { + final Future future = scheduledService.singleFixedDelayTask(1); + assertEquals(2, future.get(200, TimeUnit.MILLISECONDS).intValue()); + + } + + @Test + public void periodicFixedDelayTask() { + } +} \ No newline at end of file From 934814e368b0f566c30b67168724ab611e0b97b2 Mon Sep 17 00:00:00 2001 From: brunobat Date: Tue, 4 Dec 2018 11:04:32 +0000 Subject: [PATCH 5/8] TOMEE-2301 - Scheduler executor and exception handling examples. Signed-off-by: brunobat --- .../executor/ManagedScheduledService.java | 9 ++-- .../executor/ManagedScheduledServiceTest.java | 52 +++++++++++++++++-- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java index 1032f51e75e..07760a3dcf6 100644 --- a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java @@ -34,13 +34,14 @@ public class ManagedScheduledService { @Resource private ManagedScheduledExecutorService executor; - public Future singleFixedDelayTask(final int value) { + public Future singleFixedDelayTask(final int value, final String errorMessage) { System.out.println("longCallableTask scheduled"); - return executor.schedule(longCallableTask(value, 10, null), 100, TimeUnit.MILLISECONDS); + return executor.schedule(longCallableTask(value, 10, errorMessage), 100, TimeUnit.MILLISECONDS); } - public ScheduledFuture periodicFixedDelayTask(final int value) { - return executor.scheduleAtFixedRate(longRunnableTask(value, 10, null), 0, 100, TimeUnit.MILLISECONDS); + public ScheduledFuture periodicFixedDelayTask(final int value, final String errorMessage) { + System.out.println("longRunnableTask scheduled"); + return executor.scheduleAtFixedRate(longRunnableTask(value, 10, errorMessage), 0, 100, TimeUnit.MILLISECONDS); } private Runnable longRunnableTask(final int value, diff --git a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java index b4e3807538e..4baf428f21c 100644 --- a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java +++ b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java @@ -27,10 +27,12 @@ import javax.inject.Inject; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; @RunWith(Arquillian.class) public class ManagedScheduledServiceTest { @@ -48,12 +50,56 @@ public static final WebArchive app() { @Test public void singleFixedDelayTask() throws InterruptedException, ExecutionException, TimeoutException { - final Future future = scheduledService.singleFixedDelayTask(1); - assertEquals(2, future.get(200, TimeUnit.MILLISECONDS).intValue()); + final Future futureA = scheduledService.singleFixedDelayTask(1, null); + final Future futureB = scheduledService.singleFixedDelayTask(50, null); + System.out.println("Do some other work while we wait for the tasks"); + assertEquals(2, futureA.get(200, TimeUnit.MILLISECONDS).intValue()); + assertEquals(51, futureB.get(200, TimeUnit.MILLISECONDS).intValue()); } @Test - public void periodicFixedDelayTask() { + public void periodicFixedDelayTask() throws InterruptedException, TimeoutException, ExecutionException { + final ScheduledFuture scheduledFuture = scheduledService.periodicFixedDelayTask(1, null); + TimeUnit.MILLISECONDS.sleep(500); + if (!scheduledFuture.isCancelled()) { + scheduledFuture.cancel(true); + System.out.println("task stopped"); + } } + + + @Test + public void singleFixedDelayTaskWithException() throws InterruptedException, ExecutionException, TimeoutException { + final Future future = scheduledService.singleFixedDelayTask(1, "Planned exception"); + try { + future.get(200, TimeUnit.MILLISECONDS); + } catch (ExecutionException e) { + // the thrown RuntimeException will be wrapped around an ExecutionException + assertEquals("Planned exception", e.getCause().getMessage()); + } catch (Exception e) { + fail("Unexpected exception" + e); + } + } + + @Test + public void periodicFixedDelayTaskWithException() throws InterruptedException { + final ScheduledFuture scheduledFuture = scheduledService.periodicFixedDelayTask(1, "Planned exception"); + TimeUnit.MILLISECONDS.sleep(500); + + try { + scheduledFuture.get(200, TimeUnit.MILLISECONDS); + } catch (ExecutionException e) { + // the thrown RuntimeException will be wrapped around an ExecutionException + assertEquals("Planned exception", e.getCause().getMessage()); + } catch (Exception e) { + fail("Unexpected exception" + e); + } + + if (!scheduledFuture.isCancelled()) { + scheduledFuture.cancel(true); + System.out.println("task stopped"); + } + } + } \ No newline at end of file From ce01d8d9b362e56a121925dd070dba53290d6ffc Mon Sep 17 00:00:00 2001 From: brunobat Date: Tue, 4 Dec 2018 11:43:47 +0000 Subject: [PATCH 6/8] TOMEE-2301 - Add javadoc and use a Logger instead of System.out.println Signed-off-by: brunobat --- examples/concurrency-utils/pom.xml | 2 +- .../executor/ManagedScheduledService.java | 67 ++++++++++++++++--- .../org/superbiz/executor/ManagedService.java | 11 +-- .../executor/ManagedScheduledServiceTest.java | 41 +++++++++--- .../superbiz/executor/ManagedServiceTest.java | 5 +- 5 files changed, 101 insertions(+), 25 deletions(-) diff --git a/examples/concurrency-utils/pom.xml b/examples/concurrency-utils/pom.xml index 0e0fba60120..8a9de664921 100644 --- a/examples/concurrency-utils/pom.xml +++ b/examples/concurrency-utils/pom.xml @@ -56,7 +56,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.7.1 + 3.7.0 1.8 1.8 diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java index 07760a3dcf6..e5c1e75bd78 100644 --- a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java @@ -24,6 +24,7 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; import static java.util.Objects.nonNull; @@ -31,41 +32,85 @@ @RequestScoped public class ManagedScheduledService { + private static final Logger LOGGER = Logger.getLogger(ManagedScheduledService.class.getSimpleName()); + @Resource private ManagedScheduledExecutorService executor; - public Future singleFixedDelayTask(final int value, final String errorMessage) { - System.out.println("longCallableTask scheduled"); - return executor.schedule(longCallableTask(value, 10, errorMessage), 100, TimeUnit.MILLISECONDS); + /** + * Execute a task after a planned delay and get the result back by using a {@link Callable} + * + * @param value The value to compute + * @param errorMessage If not null an exception with be thrown with this message + * @return the processed result + */ + public Future singleFixedDelayTask(final int value, + final String errorMessage) { + LOGGER.info("longCallableTask scheduled"); + return executor.schedule( + longCallableTask(value, 10, errorMessage), 100, TimeUnit.MILLISECONDS); } - public ScheduledFuture periodicFixedDelayTask(final int value, final String errorMessage) { - System.out.println("longRunnableTask scheduled"); - return executor.scheduleAtFixedRate(longRunnableTask(value, 10, errorMessage), 0, 100, TimeUnit.MILLISECONDS); + /** + * Execute a task periodically. Although a future is returned, it will not contain a result because the + * executor uses a runnable to perform the operations.
+ * If an exception happens, the task will stop and you can catch the exception with the {@link ScheduledFuture}. + * + * @param value The value to compute + * @param errorMessage If not null an exception with be thrown with this message + * @return An object where you can cancel the periodic task and check for exceptions. + */ + public ScheduledFuture periodicFixedDelayTask(final int value, + final String errorMessage) { + LOGGER.info("longRunnableTask scheduled"); + return executor.scheduleAtFixedRate( + longRunnableTask(value, 10, errorMessage), 0, 100, TimeUnit.MILLISECONDS); } + /** + * Will simulate a long running operation + * + * @param value The value to compute + * @param taskDurationMs the time lenght of the operation + * @param errorMessage If not null an exception with be thrown with this message + * @return a {@link Runnable} + */ private Runnable longRunnableTask(final int value, final int taskDurationMs, final String errorMessage) { return () -> { if (nonNull(errorMessage)) { - System.out.println("Exception will be thrown"); + LOGGER.severe("Exception will be thrown"); throw new RuntimeException(errorMessage); } + try { + // Simulate a long processing task using TimeUnit to sleep. + TimeUnit.MILLISECONDS.sleep(taskDurationMs); + } catch (InterruptedException e) { + throw new RuntimeException("Problem while waiting"); + } Integer result = value + 1; - System.out.println("longRunnableTask complete. Value is " + result); + LOGGER.info("longRunnableTask complete. Value is " + result); // Cannot return result with a Runnable. }; } + /** + * Will simulate a long running operation + * + * @param value The value to compute + * @param taskDurationMs the time lenght of the operation + * @param errorMessage If not null an exception with be thrown with this message + * @return a {@link Callable} with the result + */ private Callable longCallableTask(final int value, final int taskDurationMs, final String errorMessage) { return () -> { - System.out.println("longCallableTask start"); + LOGGER.info("longCallableTask start"); if (nonNull(errorMessage)) { - System.out.println("Exception will be thrown"); + LOGGER.severe("Exception will be thrown"); throw new RuntimeException(errorMessage); } @@ -75,7 +120,7 @@ private Callable longCallableTask(final int value, } catch (InterruptedException e) { throw new RuntimeException("Problem while waiting"); } - System.out.println("longCallableTask complete"); + LOGGER.info("longCallableTask complete"); // We can return a result with a Callable. return value + 1; }; diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java index eecbb46d198..a8aa2cb077c 100644 --- a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java @@ -23,6 +23,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.logging.Logger; import static java.util.Objects.nonNull; @@ -30,6 +31,8 @@ @RequestScoped public class ManagedService { + private static final Logger LOGGER = Logger.getLogger(ManagedService.class.getSimpleName()); + @Resource private ManagedExecutorService executor; @@ -41,7 +44,7 @@ public class ManagedService { * @return A {@link CompletableFuture} that will return immediately. */ public CompletableFuture asyncTask(final int value) { - System.out.println("Create asyncTask"); + LOGGER.info("Create asyncTask"); return CompletableFuture .supplyAsync(longTask(value, 100, null), executor) // Execute asynchronously. .thenApply(i -> i + 1); // After the return of the task, do something else with the result. @@ -55,7 +58,7 @@ public CompletableFuture asyncTask(final int value) { * @return A {@link CompletableFuture} that will return immediately. */ public CompletableFuture asyncTaskWithException(final int value) { - System.out.println("Create asyncTaskWithException"); + LOGGER.info("Create asyncTaskWithException"); return CompletableFuture .supplyAsync(longTask(value, 100, "Planned exception"), executor) // Execute asynchronously. .thenApply(i -> i + 1); // After the return of the task, do something else with the result. @@ -74,7 +77,7 @@ private Supplier longTask(final int value, final String errorMessage) { return () -> { if (nonNull(errorMessage)) { - System.out.println("Exception will be thrown"); + LOGGER.severe("Exception will be thrown"); throw new RuntimeException(errorMessage); } @@ -84,7 +87,7 @@ private Supplier longTask(final int value, } catch (InterruptedException e) { throw new RuntimeException("Problem while waiting"); } - System.out.println("longTask complete"); + LOGGER.info("longTask complete"); return value + 1; }; } diff --git a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java index 4baf428f21c..1a859bad3ec 100644 --- a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java +++ b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedScheduledServiceTest.java @@ -30,6 +30,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -37,6 +38,8 @@ @RunWith(Arquillian.class) public class ManagedScheduledServiceTest { + private static final Logger LOGGER = Logger.getLogger(ManagedScheduledServiceTest.class.getSimpleName()); + @Inject private ManagedScheduledService scheduledService; @@ -48,29 +51,44 @@ public static final WebArchive app() { } + /** + * Happy path with multiple tasks to be executed after a planed amount of time. + * + * @throws InterruptedException we don't expect it + * @throws ExecutionException we don't expect it + * @throws TimeoutException we don't expect it + */ @Test public void singleFixedDelayTask() throws InterruptedException, ExecutionException, TimeoutException { final Future futureA = scheduledService.singleFixedDelayTask(1, null); final Future futureB = scheduledService.singleFixedDelayTask(50, null); - System.out.println("Do some other work while we wait for the tasks"); + LOGGER.info("Do some other work while we wait for the tasks"); assertEquals(2, futureA.get(200, TimeUnit.MILLISECONDS).intValue()); assertEquals(51, futureB.get(200, TimeUnit.MILLISECONDS).intValue()); } + /** + * Happy path with single task to be executed periodically until it's canceled. + * + * @throws InterruptedException we don't expect it + */ @Test - public void periodicFixedDelayTask() throws InterruptedException, TimeoutException, ExecutionException { + public void periodicFixedDelayTask() throws InterruptedException { final ScheduledFuture scheduledFuture = scheduledService.periodicFixedDelayTask(1, null); + LOGGER.info("Do some other work while we wait for the tasks"); TimeUnit.MILLISECONDS.sleep(500); if (!scheduledFuture.isCancelled()) { scheduledFuture.cancel(true); - System.out.println("task stopped"); + LOGGER.info("task stopped"); } } - + /** + * Exception happens while processing the task executed after a planed amount of time. + */ @Test - public void singleFixedDelayTaskWithException() throws InterruptedException, ExecutionException, TimeoutException { + public void singleFixedDelayTaskWithException() { final Future future = scheduledService.singleFixedDelayTask(1, "Planned exception"); try { future.get(200, TimeUnit.MILLISECONDS); @@ -82,12 +100,19 @@ public void singleFixedDelayTaskWithException() throws InterruptedException, Exe } } + /** + * Exception happens while processing the periodic task. + * + * @throws InterruptedException we don't expect it + */ @Test - public void periodicFixedDelayTaskWithException() throws InterruptedException { + public void periodicFixedDelayTaskWithException() { final ScheduledFuture scheduledFuture = scheduledService.periodicFixedDelayTask(1, "Planned exception"); - TimeUnit.MILLISECONDS.sleep(500); try { + TimeUnit.MILLISECONDS.sleep(500); + // please note that this thread will pause here until an exception is thrown. + // The scheduler uses a Runnable that will never return a result. scheduledFuture.get(200, TimeUnit.MILLISECONDS); } catch (ExecutionException e) { // the thrown RuntimeException will be wrapped around an ExecutionException @@ -98,7 +123,7 @@ public void periodicFixedDelayTaskWithException() throws InterruptedException { if (!scheduledFuture.isCancelled()) { scheduledFuture.cancel(true); - System.out.println("task stopped"); + LOGGER.info("task stopped"); } } diff --git a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java index 30b6f6fcedc..8ab7138d489 100644 --- a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java +++ b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ManagedServiceTest.java @@ -30,6 +30,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -38,6 +39,8 @@ @RunWith(Arquillian.class) public class ManagedServiceTest { + private static final Logger LOGGER = Logger.getLogger(ManagedServiceTest.class.getName()); + @Inject private ManagedService managedService; @@ -54,7 +57,7 @@ public static final WebArchive app() { @Test public void managedInvocationTest() { final CompletableFuture future = managedService.asyncTask(1); - System.out.println("You can do something else in the meantime and later get the future value"); + LOGGER.info("You can do something else in the meantime and later get the future value"); try { // To prevent hanged tasks, you should obtain the value of a future with a timeout. assertEquals(3, future.get(200, TimeUnit.MILLISECONDS).intValue()); From e96315bbf5b2ccb40866e0155132129b229306ca Mon Sep 17 00:00:00 2001 From: brunobat Date: Wed, 5 Dec 2018 15:25:54 +0000 Subject: [PATCH 7/8] TOMEE-2301 - Add Thread factory example and fix some typos Signed-off-by: brunobat --- .../executor/ManagedScheduledService.java | 2 +- .../org/superbiz/executor/ManagedService.java | 4 +- .../executor/ThreadFactoryService.java | 71 +++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 examples/concurrency-utils/src/main/java/org/superbiz/executor/ThreadFactoryService.java diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java index e5c1e75bd78..c0f2bdbc54f 100644 --- a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedScheduledService.java @@ -71,7 +71,7 @@ public ScheduledFuture periodicFixedDelayTask(final int value, * Will simulate a long running operation * * @param value The value to compute - * @param taskDurationMs the time lenght of the operation + * @param taskDurationMs the time length of the operation * @param errorMessage If not null an exception with be thrown with this message * @return a {@link Runnable} */ diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java index a8aa2cb077c..dabcf685e38 100644 --- a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ManagedService.java @@ -37,7 +37,7 @@ public class ManagedService { private ManagedExecutorService executor; /** - * Executes an opperation asynchronously, in a different thread provided by the {@link ManagedExecutorService}. + * Executes an operation asynchronously, in a different thread provided by the {@link ManagedExecutorService}. * The computation will carry on after the return of the method. * * @param value The demo data. @@ -51,7 +51,7 @@ public CompletableFuture asyncTask(final int value) { } /** - * Executes an opperation asynchronously, in a different thread provided by the {@link ManagedExecutorService}. + * Executes an operation asynchronously, in a different thread provided by the {@link ManagedExecutorService}. * The computation will carry on after the return of the method. * * @param value The demo data. diff --git a/examples/concurrency-utils/src/main/java/org/superbiz/executor/ThreadFactoryService.java b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ThreadFactoryService.java new file mode 100644 index 00000000000..17086e5d091 --- /dev/null +++ b/examples/concurrency-utils/src/main/java/org/superbiz/executor/ThreadFactoryService.java @@ -0,0 +1,71 @@ +package org.superbiz.executor; + +import javax.annotation.Resource; +import javax.enterprise.concurrent.ManagedThreadFactory; +import javax.enterprise.context.RequestScoped; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import static java.util.Objects.nonNull; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@RequestScoped +public class ThreadFactoryService { + + private static final Logger LOGGER = Logger.getLogger(ThreadFactoryService.class.getSimpleName()); + + @Resource + private ManagedThreadFactory factory; + + public void asyncTask(final int value) { + LOGGER.info("Create asyncTask"); + final Thread thread = factory.newThread(longRunnableTask(value, 100, null)); + thread.setName("pretty asyncTask"); + thread.start(); + } + + /** + * Will simulate a long running operation + * + * @param value The value to compute + * @param taskDurationMs the time length of the operation + * @param errorMessage If not null an exception with be thrown with this message + * @return a {@link Runnable} + */ + private Runnable longRunnableTask(final int value, + final int taskDurationMs, + final String errorMessage) { + return () -> { + if (nonNull(errorMessage)) { + LOGGER.severe("Exception will be thrown"); + throw new RuntimeException(errorMessage); + } + try { + // Simulate a long processing task using TimeUnit to sleep. + TimeUnit.MILLISECONDS.sleep(taskDurationMs); + } catch (InterruptedException e) { + throw new RuntimeException("Problem while waiting"); + } + + Integer result = value + 1; + LOGGER.info("longRunnableTask complete. Value is " + result); + // Cannot return result with a Runnable. + }; + } + +} From 2aaca11108805c73cd1b86fb7f0a2cc4af5d92b2 Mon Sep 17 00:00:00 2001 From: brunobat Date: Wed, 5 Dec 2018 15:26:36 +0000 Subject: [PATCH 8/8] TOMEE-2301 - add test fo the thread factory service Signed-off-by: brunobat --- .../executor/ThreadFactoryServiceTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 examples/concurrency-utils/src/test/java/org/superbiz/executor/ThreadFactoryServiceTest.java diff --git a/examples/concurrency-utils/src/test/java/org/superbiz/executor/ThreadFactoryServiceTest.java b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ThreadFactoryServiceTest.java new file mode 100644 index 00000000000..8518c283778 --- /dev/null +++ b/examples/concurrency-utils/src/test/java/org/superbiz/executor/ThreadFactoryServiceTest.java @@ -0,0 +1,53 @@ +package org.superbiz.executor; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.inject.Inject; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@RunWith(Arquillian.class) +public class ThreadFactoryServiceTest { + + private static final Logger LOGGER = Logger.getLogger(ThreadFactoryServiceTest.class.getSimpleName()); + + @Inject + private ThreadFactoryService factoryService; + + @Deployment() + public static final WebArchive app() { + return ShrinkWrap.create(WebArchive.class, "example.war") + .addClasses(ThreadFactoryService.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); + } + + @Test + public void asyncTask() throws InterruptedException { + + factoryService.asyncTask(1); + LOGGER.info("Do something else"); + TimeUnit.MILLISECONDS.sleep(200); + } +} \ No newline at end of file