diff --git a/api/pom.xml b/api/pom.xml index ac0bad34..08019b3a 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -331,6 +331,16 @@ + + jakarta.annotation + jakarta.annotation-api + 2.0.0 + + + jakarta.transaction + jakarta.transaction-api + 2.0.0 + junit junit diff --git a/api/src/main/java/jakarta/enterprise/concurrent/ContextServiceDefinition.java b/api/src/main/java/jakarta/enterprise/concurrent/ContextServiceDefinition.java new file mode 100644 index 00000000..4023df59 --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/concurrent/ContextServiceDefinition.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.transaction.UserTransaction; + +/** + *

Defines a {@link ContextService} + * to be registered in JNDI by the container + * under the JNDI name that is specified in the + * {@link #name()} attribute.

+ * + *

Application components can refer to this JNDI name in the + * {@link jakarta.annotation.Resource#lookup() lookup} attribute of a + * {@link jakarta.annotation.Resource} annotation,

+ * + *
{@literal @}ContextServiceDefinition(
+ *     name = "java:app/concurrent/MyContext",
+ *     propagated = APPLICATION,
+ *     unchanged = TRANSACTION,
+ *     cleared = ALL_REMAINING)
+ * public class MyServlet extends HttpServlet {
+ *    {@literal @}Resource(lookup = "java:app/concurrent/MyContext",
+ *               name = "java:app/concurrent/env/MyContextRef")
+ *     ContextService appContextSvc;
+ * 
+ * + *

Resource environment references in a deployment descriptor + * can similarly specify the lookup-name,

+ * + *
+ * <resource-env-ref>
+ *    <resource-env-ref-name>java:app/env/concurrent/MyContextRef</resource-env-ref-name>
+ *    <resource-env-ref-type>jakarta.enterprise.concurrent.ContextService</resource-env-ref-type>
+ *    <lookup-name>java:app/concurrent/MyContext</lookup-name>
+ * </resource-env-ref>
+ * 
+ * + *

The {@link #cleared()}, {@link #propagated()}, and {@link #unchanged()} + * attributes enable the application to configure how thread context + * is applied to tasks and actions that are contextualized by the + * ContextService. + * Constants are provided on this class for context types that are + * defined by the Jakarta EE Concurrency specification. + * In addition to those constants, a Jakarta EE product provider + * may choose to accept additional vendor-specific context types. + * Usage of vendor-specific types will make applications non-portable.

+ * + *

Overlap of the same context type across multiple lists is an error and + * prevents the ContextService instance from being created. + * If {@link #ALL_REMAINING} is not present in any of the lists, it is + * implicitly appended to the {@link #cleared()} context types.

+ * + * @since 3.0 + */ +// TODO could mention relation with definition in deployment descriptor once that is added +@Repeatable(ContextServiceDefinition.List.class) +@Retention(RUNTIME) +@Target(TYPE) +public @interface ContextServiceDefinition { + /** + *

JNDI name of the {@link ContextService} instance being defined. + * The JNDI name must be in a valid Jakarta EE namespace, + * such as,

+ * + *
    + *
  • java:comp
  • + *
  • java:module
  • + *
  • java:app
  • + *
  • java:global
  • + *
+ * + * @return ContextService JNDI name. + */ + String name(); + + /** + *

Types of context to clear whenever a thread runs the + * contextual task or action. The thread's previous context + * is restored afterward. + * + *

Constants are provided on this class for the context types + * that are defined by the Jakarta EE Concurrency specification.

+ * + * @return context types to clear. + */ + String[] cleared() default { TRANSACTION }; + + /** + *

Types of context to capture from the requesting thread + * and propagate to a thread that runs the contextual task + * or action. + * The captured context is re-established when threads + * run the contextual task or action, with the respective + * thread's previous context being restored afterward. + * + *

Constants are provided on this class for the context types + * that are defined by the Jakarta EE Concurrency specification.

+ * + * @return context types to capture and propagate. + */ + String[] propagated() default { ALL_REMAINING }; + + /** + *

Types of context that are left alone when a thread + * runs the contextual task or action.

+ * + *

Constants are provided on this class for the context types + * that are defined by the Jakarta EE Concurrency specification.

+ * + * @return context types to leave unchanged. + */ + String[] unchanged() default {}; + + /** + *

All available thread context types that are not specified + * elsewhere.

+ * + *

For example, to define a ContextService that + * propagates {@link #SECURITY} context, + * leaves {@link #TRANSACTION} context alone, + * and clears every other context type:

+ * + *
{@literal @}ContextServiceDefinition(
+     *     name = "java:module/concurrent/SecurityContext",
+     *     propagated = SECURITY,
+     *     unchanged = TRANSACTION,
+     *     cleared = ALL_REMAINING)
+     * public class MyServlet extends HttpServlet ...
+     * 
+ */ + static final String ALL_REMAINING = "Remaining"; + + /** + *

Context pertaining to the application component or module, + * including its Jakarta EE namespace (such as + * java:comp/env/) and thread context class loader.

+ * + *

A cleared application context means that the thread is + * not associated with any application component and lacks + * access to the Jakarta EE namespace and thread context class + * loader of the application.

+ */ + static final String APPLICATION = "Application"; + + // TODO: CDI context is the topic of + // https://github.com/eclipse-ee4j/concurrency-api/issues/105 + + /** + *

Context that controls the credentials that are associated + * with the thread, including the caller subject and + * invocation/RunAs subject.

+ * + *

A cleared security context gives the thread unauthenticated + * subjects.

+ */ + static final String SECURITY = "Security"; + + /** + *

Context that controls the transaction that is associated + * with the thread.

+ * + *

A thread with a cleared transaction context can begin + * a new {@link jakarta.transaction.UserTransaction}.

+ * + *

The execution property, {@link ManagedTask#TRANSACTION}, + * if specified, takes precedence over the behavior for + * transaction context that is specified on the resource + * definition annotations.

+ * + *

Jakarta EE providers need not support the propagation + * of transactions to other threads and can reject resource + * definition annotations that include transaction as a + * propagated context.

+ */ + // TODO the last item above is the topic of + // https://github.com/eclipse-ee4j/concurrency-api/issues/102 + // and can be updated accordingly when that capability is added. + static final String TRANSACTION = "Transaction"; + + /** + * Enables multiple ContextServiceDefinition + * annotations on the same type. + */ + @Retention(RUNTIME) + @Target(TYPE) + public @interface List { + ContextServiceDefinition[] value(); + } +} diff --git a/api/src/main/java/jakarta/enterprise/concurrent/ManagedExecutorDefinition.java b/api/src/main/java/jakarta/enterprise/concurrent/ManagedExecutorDefinition.java new file mode 100644 index 00000000..46ea1eda --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/concurrent/ManagedExecutorDefinition.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + *

Defines a {@link ManagedExecutorService} + * to be registered in JNDI by the container + * under the JNDI name that is specified in the + * {@link #name()} attribute.

+ * + *

Application components can refer to this JNDI name in the + * {@link jakarta.annotation.Resource#lookup() lookup} attribute of a + * {@link jakarta.annotation.Resource} annotation,

+ * + *
{@literal @}ManagedExecutorDefinition(
+ *     name = "java:module/concurrent/MyExecutor",
+ *     hungTaskThreshold = 120000,
+ *     maxAsync = 5,
+ *     context ={@literal @}ContextServiceDefinition(
+ *               name = "java:module/concurrent/MyExecutorContext",
+ *               propagated = { SECURITY, APPLICATION }))
+ * public class MyServlet extends HttpServlet {
+ *    {@literal @}Resource(lookup = "java:module/concurrent/MyExecutor",
+ *               name = "java:module/concurrent/env/MyExecutorRef")
+ *     ManagedExecutorService myExecutor;
+ * 
+ * + *

Resource environment references in a deployment descriptor + * can similarly specify the lookup-name,

+ * + *
+ * <resource-env-ref>
+ *    <resource-env-ref-name>java:module/env/concurrent/MyExecutorRef</resource-env-ref-name>
+ *    <resource-env-ref-type>jakarta.enterprise.concurrent.ManagedExecutorService</resource-env-ref-type>
+ *    <lookup-name>java:module/concurrent/MyExecutor</lookup-name>
+ * </resource-env-ref>
+ * 
+ * + * @since 3.0 + */ +//TODO could mention relation with definition in deployment descriptor once that is added +@Repeatable(ManagedExecutorDefinition.List.class) +@Retention(RUNTIME) +@Target(TYPE) +public @interface ManagedExecutorDefinition { + /** + * JNDI name of the {@link ManagedExecutorService} instance. + * The JNDI name must be in a valid Jakarta EE namespace, + * such as, + *
    + *
  • java:comp
  • + *
  • java:module
  • + *
  • java:app
  • + *
  • java:global
  • + *
+ * + * @return ManagedExecutorService JNDI name. + */ + String name(); + + /** + *

Determines how context is applied to tasks and actions that + * run on this executor.

+ * + *

The default value indicates to use the default instance of + * {@link ContextService} by specifying a + * {@link ContextServiceDefinition} with the name + * java:comp/DefaultContextService.

+ * + * @return instructions for capturing and propagating or clearing context. + */ + ContextServiceDefinition context() default @ContextServiceDefinition(name = "java:comp/DefaultContextService"); + + /** + *

The amount of time in milliseconds that a task or action + * can execute before it is considered hung.

+ * + *

The default value of -1 indicates unlimited.

+ * + * @return number of milliseconds after which a task or action + * is considered hung. + */ + long hungTaskThreshold() default -1; + + /** + *

Upper bound on contextual tasks and actions that this executor + * will simultaneously execute asynchronously. This constraint does + * not apply to tasks and actions that the executor runs inline, + * such as when a thread requests + * {@link java.util.concurrent.CompletableFuture#join()} and the + * action runs inline if it has not yet started.

+ * + *

The default value of -1 indicates unbounded, + * although still subject to resource constraints of the system.

+ * + * @return upper limit on asynchronous execution. + */ + int maxAsync() default -1; + + /** + * Enables multiple ManagedExecutorDefinition + * annotations on the same type. + */ + @Retention(RUNTIME) + @Target(TYPE) + public @interface List { + ManagedExecutorDefinition[] value(); + } +} diff --git a/api/src/main/java/jakarta/enterprise/concurrent/ManagedScheduledExecutorDefinition.java b/api/src/main/java/jakarta/enterprise/concurrent/ManagedScheduledExecutorDefinition.java new file mode 100644 index 00000000..8a8462ce --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/concurrent/ManagedScheduledExecutorDefinition.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + *

Defines a {@link ManagedScheduledExecutorService} + * to be registered in JNDI by the container + * under the JNDI name that is specified in the + * {@link #name()} attribute.

+ * + *

Application components can refer to this JNDI name in the + * {@link jakarta.annotation.Resource#lookup() lookup} attribute of a + * {@link jakarta.annotation.Resource} annotation,

+ * + *
{@literal @}ManagedScheduledExecutorDefinition(
+ *     name = "java:comp/concurrent/MyScheduledExecutor",
+ *     hungTaskThreshold = 30000,
+ *     maxAsync = 3,
+ *     context ={@literal @}ContextServiceDefinition(
+ *               name = "java:comp/concurrent/MyScheduledExecutorContext",
+ *               propagated = APPLICATION))
+ * public class MyServlet extends HttpServlet {
+ *    {@literal @}Resource(lookup = "java:comp/concurrent/MyScheduledExecutor",
+ *               name = "java:comp/concurrent/env/MyScheduledExecutorRef")
+ *     ManagedScheduledExecutorService myScheduledExecutor;
+ * 
+ * + *

Resource environment references in a deployment descriptor + * can similarly specify the lookup-name,

+ * + *
+ * <resource-env-ref>
+ *    <resource-env-ref-name>java:comp/env/concurrent/MyScheduledExecutorRef</resource-env-ref-name>
+ *    <resource-env-ref-type>jakarta.enterprise.concurrent.ManagedScheduledExecutorService</resource-env-ref-type>
+ *    <lookup-name>java:comp/concurrent/MyScheduledExecutor</lookup-name>
+ * </resource-env-ref>
+ * 
+ * + * @since 3.0 + */ +//TODO could mention relation with definition in deployment descriptor once that is added +@Repeatable(ManagedScheduledExecutorDefinition.List.class) +@Retention(RUNTIME) +@Target(TYPE) +public @interface ManagedScheduledExecutorDefinition { + /** + * JNDI name of the {@link ManagedScheduledExecutorService} instance. + * The JNDI name must be in a valid Jakarta EE namespace, + * such as, + *
    + *
  • java:comp
  • + *
  • java:module
  • + *
  • java:app
  • + *
  • java:global
  • + *
+ * + * @return ManagedScheduledExecutorService JNDI name. + */ + String name(); + + /** + *

Determines how context is applied to tasks and actions that + * run on this executor.

+ * + *

The default value indicates to use the default instance of + * {@link ContextService} by specifying a + * {@link ContextServiceDefinition} with the name + * java:comp/DefaultContextService.

+ * + * @return instructions for capturing and propagating or clearing context. + */ + ContextServiceDefinition context() default @ContextServiceDefinition(name = "java:comp/DefaultContextService"); + + /** + *

The amount of time in milliseconds that a task or action + * can execute before it is considered hung.

+ * + *

The default value of -1 indicates unlimited.

+ * + * @return number of milliseconds after which a task or action + * is considered hung. + */ + long hungTaskThreshold() default -1; + + /** + *

Upper bound on contextual tasks and actions that this executor + * will simultaneously execute asynchronously. This constraint does + * not apply to tasks and actions that the executor runs inline, + * such as when a thread requests + * {@link java.util.concurrent.CompletableFuture#join()} and the + * action runs inline if it has not yet started. + * This constraint also does not apply to tasks that are scheduled + * via the schedule* methods.

+ * + *

The default value of -1 indicates unbounded, + * although still subject to resource constraints of the system.

+ * + * @return upper limit on asynchronous execution. + */ + int maxAsync() default -1; + + /** + * Enables multiple ManagedScheduledExecutorDefinition + * annotations on the same type. + */ + @Retention(RUNTIME) + @Target(TYPE) + public @interface List { + ManagedScheduledExecutorDefinition[] value(); + } +} diff --git a/api/src/main/java/jakarta/enterprise/concurrent/ManagedThreadFactoryDefinition.java b/api/src/main/java/jakarta/enterprise/concurrent/ManagedThreadFactoryDefinition.java new file mode 100644 index 00000000..98ee3534 --- /dev/null +++ b/api/src/main/java/jakarta/enterprise/concurrent/ManagedThreadFactoryDefinition.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + *

Defines a {@link ManagedThreadFactory} + * to be registered in JNDI by the container + * under the JNDI name that is specified in the + * {@link #name()} attribute.

+ * + *

Application components can refer to this JNDI name in the + * {@link jakarta.annotation.Resource#lookup() lookup} attribute of a + * {@link jakarta.annotation.Resource} annotation,

+ * + *
{@literal @}ManagedThreadFactoryDefinition(
+ *     name = "java:global/concurrent/MyThreadFactory",
+ *     priority = "4",
+ *     context ={@literal @}ContextServiceDefinition(
+ *               name = "java:global/concurrent/MyThreadFactoryContext",
+ *               propagated = APPLICATION))
+ * public class MyServlet extends HttpServlet {
+ *    {@literal @}Resource(lookup = "java:global/concurrent/MyThreadFactory",
+ *               name = "java:module/concurrent/env/MyThreadFactoryRef")
+ *     ManagedThreadFactory myThreadFactory;
+ * 
+ * + *

Resource environment references in a deployment descriptor + * can similarly specify the lookup-name,

+ * + *
+ * <resource-env-ref>
+ *    <resource-env-ref-name>java:module/env/concurrent/MyThreadFactoryRef</resource-env-ref-name>
+ *    <resource-env-ref-type>jakarta.enterprise.concurrent.ManagedThreadFactory</resource-env-ref-type>
+ *    <lookup-name>java:global/concurrent/MyThreadFactory</lookup-name>
+ * </resource-env-ref>
+ * 
+ * + * @since 3.0 + */ +//TODO could mention relation with definition in deployment descriptor once that is added +@Repeatable(ManagedThreadFactoryDefinition.List.class) +@Retention(RUNTIME) +@Target(TYPE) +public @interface ManagedThreadFactoryDefinition { + /** + * JNDI name of the {@link ManagedThreadFactory} instance. + * The JNDI name must be in a valid Jakarta EE namespace, + * such as, + *
    + *
  • java:comp
  • + *
  • java:module
  • + *
  • java:app
  • + *
  • java:global
  • + *
+ * + * @return ManagedThreadFactory JNDI name. + */ + String name(); + + /** + *

Determines how context is applied to threads from this + * thread factory.

+ * + *

The default value indicates to use the default instance of + * {@link ContextService} by specifying a + * {@link ContextServiceDefinition} with the name + * java:comp/DefaultContextService.

+ * + * @return instructions for capturing and propagating or clearing context. + */ + ContextServiceDefinition context() default @ContextServiceDefinition(name = "java:comp/DefaultContextService"); + + /** + *

Priority for threads created by this thread factory.

+ * + *

The default is {@link java.lang.Thread#NORM_PRIORITY}.

+ * + * @return the priority for new threads. + */ + int priority() default Thread.NORM_PRIORITY; + + /** + * Enables multiple ManagedThreadFactoryDefinition + * annotations on the same type. + */ + @Retention(RUNTIME) + @Target(TYPE) + public @interface List { + ManagedThreadFactoryDefinition[] value(); + } +} diff --git a/api/src/test/java/jakarta/enterprise/concurrent/ContextServiceDefinitionTest.java b/api/src/test/java/jakarta/enterprise/concurrent/ContextServiceDefinitionTest.java new file mode 100644 index 00000000..124c31db --- /dev/null +++ b/api/src/test/java/jakarta/enterprise/concurrent/ContextServiceDefinitionTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static jakarta.enterprise.concurrent.ContextServiceDefinition.ALL_REMAINING; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.APPLICATION; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.SECURITY; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.TRANSACTION; +import static org.junit.Assert.*; + +import jakarta.annotation.Resource; +import org.junit.Test; + +@ContextServiceDefinition( // from ContextServiceDefinition JavaDoc + name = "java:app/concurrent/MyContext", + propagated = APPLICATION, + unchanged = TRANSACTION, + cleared = ALL_REMAINING) +@ContextServiceDefinition( + name = "java:comp/concurrent/ContextServiceDefinitionDefaults") +@ContextServiceDefinition( // from ALL_REMAINING JavaDoc + name = "java:module/concurrent/SecurityContext", + propagated = SECURITY, + unchanged = TRANSACTION, + cleared = ALL_REMAINING) +public class ContextServiceDefinitionTest { + + // from ContextServiceDefinition JavaDoc + @Resource(lookup = "java:app/concurrent/MyContext", + name = "java:app/concurrent/env/MyContextRef") + ContextService appContextSvc; + + /** + * Validate the example that is used in the ALL_REMAINING JavaDoc. + */ + @Test + public void testContextServiceDefinitionALL_REMAININGJavaDocExample() throws Exception { + ContextServiceDefinition csdSecurityContext = null; + for (ContextServiceDefinition anno : ContextServiceDefinitionTest.class.getAnnotationsByType(ContextServiceDefinition.class)) + if ("java:module/concurrent/SecurityContext".equals(anno.name())) + csdSecurityContext = anno; + assertNotNull(csdSecurityContext); + assertArrayEquals(new String[] { SECURITY }, csdSecurityContext.propagated()); + assertArrayEquals(new String[] { TRANSACTION }, csdSecurityContext.unchanged()); + assertArrayEquals(new String[] { ALL_REMAINING }, csdSecurityContext.cleared()); + } + + /** + * Validate the default values for ContextServiceDefinition. + */ + @Test + public void testContextServiceDefinitionDefaultValues() throws Exception { + ContextServiceDefinition csdDefaults = null; + for (ContextServiceDefinition anno : ContextServiceDefinitionTest.class.getAnnotationsByType(ContextServiceDefinition.class)) + if ("java:comp/concurrent/ContextServiceDefinitionDefaults".equals(anno.name())) + csdDefaults = anno; + assertNotNull(csdDefaults); + assertArrayEquals(new String[] { TRANSACTION }, csdDefaults.cleared()); + assertArrayEquals(new String[] {}, csdDefaults.unchanged()); + assertArrayEquals(new String[] { ALL_REMAINING }, csdDefaults.propagated()); + } + + /** + * Validate the example that is used in ContextServiceDefinition JavaDoc. + */ + @Test + public void testContextServiceDefinitionJavaDocExample() throws Exception { + ContextServiceDefinition csdMyContext = null; + for (ContextServiceDefinition anno : ContextServiceDefinitionTest.class.getAnnotationsByType(ContextServiceDefinition.class)) + if ("java:app/concurrent/MyContext".equals(anno.name())) + csdMyContext = anno; + assertNotNull(csdMyContext); + assertArrayEquals(new String[] { APPLICATION }, csdMyContext.propagated()); + assertArrayEquals(new String[] { TRANSACTION }, csdMyContext.unchanged()); + assertArrayEquals(new String[] { ALL_REMAINING }, csdMyContext.cleared()); + } +} diff --git a/api/src/test/java/jakarta/enterprise/concurrent/ManagedExecutorDefinitionTest.java b/api/src/test/java/jakarta/enterprise/concurrent/ManagedExecutorDefinitionTest.java new file mode 100644 index 00000000..94564281 --- /dev/null +++ b/api/src/test/java/jakarta/enterprise/concurrent/ManagedExecutorDefinitionTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static jakarta.enterprise.concurrent.ContextServiceDefinition.ALL_REMAINING; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.APPLICATION; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.SECURITY; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.TRANSACTION; +import static org.junit.Assert.*; + +import jakarta.annotation.Resource; +import org.junit.Test; + +@ManagedExecutorDefinition( // from ManagedExecutorDefinition JavaDoc + name = "java:module/concurrent/MyExecutor", + hungTaskThreshold = 120000, + maxAsync = 5, + context = @ContextServiceDefinition( + name = "java:module/concurrent/MyExecutorContext", + propagated = { SECURITY, APPLICATION })) +@ManagedExecutorDefinition( + name = "java:app/concurrent/ManagedExecutorDefinitionDefaults") +public class ManagedExecutorDefinitionTest { + + // from ManagedExecutorDefinition JavaDoc + @Resource(lookup = "java:module/concurrent/MyExecutor", + name = "java:module/concurrent/env/MyExecutorRef") + ManagedExecutorService myExecutor; + + /** + * Validate the default values for ManagedExecutorDefinition. + */ + @Test + public void testManagedExecutorDefinitionDefaultValues() throws Exception { + ManagedExecutorDefinition def = null; + for (ManagedExecutorDefinition anno : ManagedExecutorDefinitionTest.class.getAnnotationsByType(ManagedExecutorDefinition.class)) + if ("java:app/concurrent/ManagedExecutorDefinitionDefaults".equals(anno.name())) + def = anno; + assertNotNull(def); + assertEquals(-1, def.hungTaskThreshold()); + assertEquals(-1, def.maxAsync()); + ContextServiceDefinition csd = def.context(); + assertEquals("java:comp/DefaultContextService", csd.name()); + assertArrayEquals(new String[] { TRANSACTION }, csd.cleared()); + assertArrayEquals(new String[] {}, csd.unchanged()); + assertArrayEquals(new String[] { ALL_REMAINING }, csd.propagated()); + } + + /** + * Validate the example that is used in ManagedExecutorDefinition JavaDoc. + */ + @Test + public void testManagedExecutorDefinitionJavaDocExample() throws Exception { + ManagedExecutorDefinition def = null; + for (ManagedExecutorDefinition anno : ManagedExecutorDefinitionTest.class.getAnnotationsByType(ManagedExecutorDefinition.class)) + if ("java:module/concurrent/MyExecutor".equals(anno.name())) + def = anno; + assertNotNull(def); + assertEquals(120000, def.hungTaskThreshold()); + assertEquals(5, def.maxAsync()); + ContextServiceDefinition csd = def.context(); + assertEquals("java:module/concurrent/MyExecutorContext", csd.name()); + assertArrayEquals(new String[] { SECURITY, APPLICATION }, csd.propagated()); + assertArrayEquals(new String[] { TRANSACTION }, csd.cleared()); + assertArrayEquals(new String[] {}, csd.unchanged()); + } +} diff --git a/api/src/test/java/jakarta/enterprise/concurrent/ManagedScheduledExecutorDefinitionTest.java b/api/src/test/java/jakarta/enterprise/concurrent/ManagedScheduledExecutorDefinitionTest.java new file mode 100644 index 00000000..4b6d519f --- /dev/null +++ b/api/src/test/java/jakarta/enterprise/concurrent/ManagedScheduledExecutorDefinitionTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static jakarta.enterprise.concurrent.ContextServiceDefinition.ALL_REMAINING; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.APPLICATION; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.SECURITY; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.TRANSACTION; +import static org.junit.Assert.*; + +import jakarta.annotation.Resource; +import org.junit.Test; + +@ManagedScheduledExecutorDefinition( // from ManagedScheduledExecutorDefinition JavaDoc + name = "java:comp/concurrent/MyScheduledExecutor", + hungTaskThreshold = 30000, + maxAsync = 3, + context = @ContextServiceDefinition( + name = "java:comp/concurrent/MyScheduledExecutorContext", + propagated = APPLICATION)) +@ManagedScheduledExecutorDefinition( + name = "java:global/concurrent/ManagedScheduledExecutorDefinitionDefaults") +public class ManagedScheduledExecutorDefinitionTest { + + // from ManagedScheduledExecutorDefinition JavaDoc + @Resource(lookup = "java:comp/concurrent/MyScheduledExecutor", + name = "java:comp/concurrent/env/MyScheduledExecutorRef") + ManagedScheduledExecutorService myScheduledExecutor; + + /** + * Validate the default values for ManagedScheduledExecutorDefinition. + */ + @Test + public void testManagedScheduledExecutorDefinitionDefaultValues() throws Exception { + ManagedScheduledExecutorDefinition def = null; + for (ManagedScheduledExecutorDefinition anno : ManagedScheduledExecutorDefinitionTest.class + .getAnnotationsByType(ManagedScheduledExecutorDefinition.class)) + if ("java:global/concurrent/ManagedScheduledExecutorDefinitionDefaults".equals(anno.name())) + def = anno; + assertNotNull(def); + assertEquals(-1, def.hungTaskThreshold()); + assertEquals(-1, def.maxAsync()); + ContextServiceDefinition csd = def.context(); + assertEquals("java:comp/DefaultContextService", csd.name()); + assertArrayEquals(new String[] { TRANSACTION }, csd.cleared()); + assertArrayEquals(new String[] {}, csd.unchanged()); + assertArrayEquals(new String[] { ALL_REMAINING }, csd.propagated()); + } + + /** + * Validate the example that is used in ManagedScheduledExecutorDefinition JavaDoc. + */ + @Test + public void testManagedScheduledExecutorDefinitionJavaDocExample() throws Exception { + ManagedScheduledExecutorDefinition def = null; + for (ManagedScheduledExecutorDefinition anno : ManagedScheduledExecutorDefinitionTest.class + .getAnnotationsByType(ManagedScheduledExecutorDefinition.class)) + if ("java:comp/concurrent/MyScheduledExecutor".equals(anno.name())) + def = anno; + assertNotNull(def); + assertEquals(30000, def.hungTaskThreshold()); + assertEquals(3, def.maxAsync()); + ContextServiceDefinition csd = def.context(); + assertEquals("java:comp/concurrent/MyScheduledExecutorContext", csd.name()); + assertArrayEquals(new String[] { APPLICATION }, csd.propagated()); + assertArrayEquals(new String[] { TRANSACTION }, csd.cleared()); + assertArrayEquals(new String[] {}, csd.unchanged()); + } +} diff --git a/api/src/test/java/jakarta/enterprise/concurrent/ManagedThreadFactoryDefinitionTest.java b/api/src/test/java/jakarta/enterprise/concurrent/ManagedThreadFactoryDefinitionTest.java new file mode 100644 index 00000000..76362e17 --- /dev/null +++ b/api/src/test/java/jakarta/enterprise/concurrent/ManagedThreadFactoryDefinitionTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.enterprise.concurrent; + +import static jakarta.enterprise.concurrent.ContextServiceDefinition.ALL_REMAINING; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.APPLICATION; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.SECURITY; +import static jakarta.enterprise.concurrent.ContextServiceDefinition.TRANSACTION; +import static org.junit.Assert.*; + +import jakarta.annotation.Resource; +import org.junit.Test; + +@ManagedThreadFactoryDefinition( // from ManagedThreadFactoryDefinition JavaDoc + name = "java:global/concurrent/MyThreadFactory", + priority = 4, + context = @ContextServiceDefinition( + name = "java:global/concurrent/MyThreadFactoryContext", + propagated = APPLICATION)) +@ManagedThreadFactoryDefinition( + name = "java:comp/concurrent/ManagedThreadFactoryDefinitionDefaults") +public class ManagedThreadFactoryDefinitionTest { + + // from ManagedThreadFactoryDefinition JavaDoc + @Resource(lookup = "java:global/concurrent/MyThreadFactory", + name = "java:module/concurrent/env/MyThreadFactoryRef") + ManagedThreadFactory myThreadFactory; + + /** + * Validate the default values for ManagedThreadFactoryDefinition. + */ + @Test + public void testManagedThreadFactoryDefinitionDefaultValues() throws Exception { + ManagedThreadFactoryDefinition def = null; + for (ManagedThreadFactoryDefinition anno : ManagedThreadFactoryDefinitionTest.class + .getAnnotationsByType(ManagedThreadFactoryDefinition.class)) + if ("java:comp/concurrent/ManagedThreadFactoryDefinitionDefaults".equals(anno.name())) + def = anno; + assertNotNull(def); + assertEquals(Thread.NORM_PRIORITY, def.priority()); + ContextServiceDefinition csd = def.context(); + assertEquals("java:comp/DefaultContextService", csd.name()); + assertArrayEquals(new String[] { TRANSACTION }, csd.cleared()); + assertArrayEquals(new String[] {}, csd.unchanged()); + assertArrayEquals(new String[] { ALL_REMAINING }, csd.propagated()); + } + + /** + * Validate the example that is used in ManagedThreadFactoryDefinition JavaDoc. + */ + @Test + public void testManagedThreadFactoryDefinitionJavaDocExample() throws Exception { + ManagedThreadFactoryDefinition def = null; + for (ManagedThreadFactoryDefinition anno : ManagedThreadFactoryDefinitionTest.class + .getAnnotationsByType(ManagedThreadFactoryDefinition.class)) + if ("java:global/concurrent/MyThreadFactory".equals(anno.name())) + def = anno; + assertNotNull(def); + assertEquals(4, def.priority()); + ContextServiceDefinition csd = def.context(); + assertEquals("java:global/concurrent/MyThreadFactoryContext", csd.name()); + assertArrayEquals(new String[] { APPLICATION }, csd.propagated()); + assertArrayEquals(new String[] { TRANSACTION }, csd.cleared()); + assertArrayEquals(new String[] {}, csd.unchanged()); + } +}