This is an automated email from the ASF dual-hosted git repository. jlmonteiro pushed a commit to branch TOMEE-4123_AroundConstruct in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 4f23fe15685b8b25fcfb3a187e1fcc9f33325ee7 Author: Jean-Louis Monteiro <jlmonte...@tomitribe.com> AuthorDate: Fri Dec 9 14:09:43 2022 +0100 Start preparing the model and a basic happy path test to support Interceptor 1.2 @AroundConstruct lifecycle callback --- .../main/java/org/apache/openejb/BeanContext.java | 17 +++++++++++++ .../openejb/assembler/classic/Assembler.java | 5 ++-- .../classic/InterceptorBindingBuilder.java | 3 +++ .../openejb/assembler/classic/InterceptorInfo.java | 1 + .../java/org/apache/openejb/cdi/CdiBeanInfo.java | 8 ++++++ .../apache/openejb/config/AnnotationDeployer.java | 12 +++++++++ .../apache/openejb/config/EjbJarInfoBuilder.java | 1 + .../java/org/apache/openejb/core/Operation.java | 1 + .../openejb/core/interceptor/InterceptorData.java | 21 ++++++++++++---- .../openejb/monitoring/StatsInterceptor.java | 14 +++++++++++ .../core/stateful/StatefulInterceptorTest.java | 29 +++++++++++++++++++++- .../java/org/apache/openejb/jee/Interceptor.java | 9 +++++++ 12 files changed, 113 insertions(+), 8 deletions(-) diff --git a/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java b/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java index 44b242d621..4d02f9fd26 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java @@ -143,8 +143,21 @@ public class BeanContext extends DeploymentContext { return; } + final Collection<Interceptor<?>> aroundConstructInterceptors = Collection.class.cast(Reflections.get(injectionTarget, "aroundConstructInterceptors")); final Collection<Interceptor<?>> postConstructInterceptors = Collection.class.cast(Reflections.get(injectionTarget, "postConstructInterceptors")); final Collection<Interceptor<?>> preDestroyInterceptors = Collection.class.cast(Reflections.get(injectionTarget, "preDestroyInterceptors")); + + if (aroundConstructInterceptors != null) { + for (final Interceptor<?> pc : aroundConstructInterceptors) { + if (isEjbInterceptor(pc)) { + continue; + } + + final InterceptorData interceptorData = createInterceptorData(pc); + instanceScopedInterceptors.add(interceptorData); + cdiInterceptors.add(interceptorData); + } + } if (postConstructInterceptors != null) { for (final Interceptor<?> pc : postConstructInterceptors) { if (isEjbInterceptor(pc)) { @@ -201,6 +214,7 @@ public class BeanContext extends DeploymentContext { Map.class.cast(Reflections.get(injectionTarget, "methodInterceptors")).clear(); clear(Collection.class.cast(postConstructInterceptors)); clear(Collection.class.cast(preDestroyInterceptors)); + clear(Collection.class.cast(Reflections.get(injectionTarget, "aroundConstructMethods"))); clear(Collection.class.cast(Reflections.get(injectionTarget, "postConstructMethods"))); clear(Collection.class.cast(Reflections.get(injectionTarget, "preDestroyMethods"))); clear(Collection.class.cast(Reflections.get(info, "ejbInterceptors"))); @@ -1594,6 +1608,9 @@ public class BeanContext extends DeploymentContext { // Create bean instance Object beanInstance; + // TODO we need to create the interceptor stack for the instance and + // invoke it to wrap what's bellow to create the beanInstance + final InjectionProcessor injectionProcessor; if (!dynamicallyImplemented) { injectionProcessor = new InjectionProcessor(rootInstance, getInjections(), InjectionProcessor.unwrap(ctx)); diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java index 2bca743fdb..dbc781dee0 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java @@ -17,6 +17,7 @@ package org.apache.openejb.assembler.classic; +import jakarta.interceptor.AroundConstruct; import org.apache.geronimo.connector.GeronimoBootstrapContext; import org.apache.geronimo.connector.outbound.AbstractConnectionManager; import org.apache.geronimo.connector.work.GeronimoWorkManager; @@ -1285,9 +1286,9 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A final AnnotationFinder finder = Proxy.isProxyClass(clazz) ? null : new AnnotationFinder(new ClassesArchive(ancestors(clazz))); final List<Method> postConstructs = finder == null ? - Collections.<Method>emptyList() : finder.findAnnotatedMethods(PostConstruct.class); + Collections.emptyList() : finder.findAnnotatedMethods(PostConstruct.class); final List<Method> preDestroys = finder == null ? - Collections.<Method>emptyList() : finder.findAnnotatedMethods(PreDestroy.class); + Collections.emptyList() : finder.findAnnotatedMethods(PreDestroy.class); resourceInfo.postConstructMethods = new ArrayList<>(); resourceInfo.preDestroyMethods = new ArrayList<>(); diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java index d8f27b25d9..4ba00f6319 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java @@ -80,6 +80,7 @@ public class InterceptorBindingBuilder { toMethods(clazz, info.aroundInvoke, interceptor.getAroundInvoke()); toMethods(clazz, info.postActivate, interceptor.getPostActivate()); toMethods(clazz, info.prePassivate, interceptor.getPrePassivate()); + toMethods(clazz, info.aroundConstruct, interceptor.getAroundConstruct()); toMethods(clazz, info.postConstruct, interceptor.getPostConstruct()); toMethods(clazz, info.preDestroy, interceptor.getPreDestroy()); toMethods(clazz, info.afterBegin, interceptor.getAfterBegin()); @@ -272,6 +273,7 @@ public class InterceptorBindingBuilder { /** * Used for getting the java.lang.reflect.Method objects for the following callbacks: * + * - @AroundConstruct <any-scope> void <method-name>(InvocationContext) * - @PostConstruct <any-scope> void <method-name>(InvocationContext) * - @PreDestroy <any-scope> void <method-name>(InvocationContext) * - @PrePassivate <any-scope> void <method-name>(InvocationContext) @@ -329,6 +331,7 @@ public class InterceptorBindingBuilder { /** * Used for getting the java.lang.reflect.Method objects for the following callbacks: * + * - @AroundConstruct <any-scope> void <method-name>() * - @PostConstruct <any-scope> void <method-name>() * - @PreDestroy <any-scope> void <method-name>() * - @PrePassivate <any-scope> void <method-name>() diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java index 9c6dc58003..715f59a31d 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java @@ -25,6 +25,7 @@ public class InterceptorInfo extends InfoObject { public final List<CallbackInfo> aroundInvoke = new ArrayList<>(); + public final List<CallbackInfo> aroundConstruct = new ArrayList<>(); public final List<CallbackInfo> postConstruct = new ArrayList<>(); public final List<CallbackInfo> preDestroy = new ArrayList<>(); diff --git a/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java b/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java index 95fb80e416..d641b4d48d 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiBeanInfo.java @@ -52,6 +52,7 @@ public class CdiBeanInfo implements JndiConsumer { protected KeyedCollection<String, MessageDestinationRef> messageDestinationRef; protected KeyedCollection<String, PersistenceContextRef> persistenceContextRef; protected KeyedCollection<String, PersistenceUnitRef> persistenceUnitRef; + protected List<LifecycleCallback> aroundConstruct; protected List<LifecycleCallback> postConstruct; protected List<LifecycleCallback> preDestroy; protected KeyedCollection<String, DataSource> dataSource; @@ -227,6 +228,13 @@ public class CdiBeanInfo implements JndiConsumer { return this.persistenceUnitRef.toMap(); } + public List<LifecycleCallback> getAroundConstruct() { + if (aroundConstruct == null) { + aroundConstruct = new ArrayList<>(); + } + return this.aroundConstruct; + } + public List<LifecycleCallback> getPostConstruct() { if (postConstruct == null) { postConstruct = new ArrayList<>(); diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java b/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java index aeef3e57ce..ed7b9032cc 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java @@ -17,6 +17,7 @@ package org.apache.openejb.config; +import jakarta.interceptor.AroundConstruct; import org.apache.openejb.BeanContext; import org.apache.openejb.OpenEJBException; import org.apache.openejb.api.LocalClient; @@ -2527,6 +2528,7 @@ public class AnnotationDeployer implements DynamicDeployer { } /* + * @AroundConstruct can't be on the bean itself per spec * @PostConstruct * @PreDestroy * @AroundInvoke @@ -2983,6 +2985,16 @@ public class AnnotationDeployer implements DynamicDeployer { */ processCallbacks(interceptor, annotationFinder); + /* + * @PAroundConstruct can only be on the interceptor itself + */ + final boolean override = "true".equalsIgnoreCase(getProperty("openejb.callbacks.override", "false")); + if (apply(override, interceptor.getAroundConstruct())) { + for (final Annotated<Method> method : sortMethods(annotationFinder.findMetaAnnotatedMethods(AroundConstruct.class))) { + interceptor.getAroundConstruct().add(new LifecycleCallback(method.get())); + } + } + /* * @ApplicationException */ diff --git a/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java b/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java index 874bca4c9f..3f0e0191c6 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java @@ -449,6 +449,7 @@ public class EjbJarInfoBuilder { copyCallbacks(s.getAroundInvoke(), info.aroundInvoke); + copyCallbacks(s.getAroundConstruct(), info.aroundConstruct); copyCallbacks(s.getPostConstruct(), info.postConstruct); copyCallbacks(s.getPreDestroy(), info.preDestroy); diff --git a/container/openejb-core/src/main/java/org/apache/openejb/core/Operation.java b/container/openejb-core/src/main/java/org/apache/openejb/core/Operation.java index 023023946a..ce0dd9199f 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/core/Operation.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/core/Operation.java @@ -19,6 +19,7 @@ package org.apache.openejb.core; public enum Operation { INJECTION(true), + AROUND_CONSTRUCT(true), POST_CONSTRUCT(true), BUSINESS(false), BUSINESS_WS(false), diff --git a/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java b/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java index a7836d8c32..35d73595e6 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java @@ -17,11 +17,6 @@ package org.apache.openejb.core.interceptor; -import org.apache.openejb.core.Operation; -import org.apache.openejb.util.SetAccessible; -import org.apache.webbeans.component.CdiInterceptorBean; -import org.apache.xbean.finder.ClassFinder; - import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import jakarta.ejb.AfterBegin; @@ -30,8 +25,14 @@ import jakarta.ejb.BeforeCompletion; import jakarta.ejb.PostActivate; import jakarta.ejb.PrePassivate; import jakarta.enterprise.inject.spi.InterceptionType; +import jakarta.interceptor.AroundConstruct; import jakarta.interceptor.AroundInvoke; import jakarta.interceptor.AroundTimeout; +import org.apache.openejb.core.Operation; +import org.apache.openejb.util.SetAccessible; +import org.apache.webbeans.component.CdiInterceptorBean; +import org.apache.xbean.finder.ClassFinder; + import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Collections; @@ -56,6 +57,7 @@ public class InterceptorData { private final Set<Method> aroundInvoke = new LinkedHashSet<>(); + private final Set<Method> aroundConstruct = new LinkedHashSet<>(); private final Set<Method> postConstruct = new LinkedHashSet<>(); private final Set<Method> preDestroy = new LinkedHashSet<>(); @@ -113,6 +115,11 @@ public class InterceptorData { return postConstruct; } + // TODO should it return a set of Constructor instead + public Set<Method> getAroundConstruct() { + return aroundConstruct; + } + public Set<Method> getPreDestroy() { return preDestroy; } @@ -149,6 +156,8 @@ public class InterceptorData { return getAroundInvoke(); case REMOVE: return getAroundInvoke(); + case AROUND_CONSTRUCT: + return getAroundConstruct(); case POST_CONSTRUCT: return getPostConstruct(); case PRE_DESTROY: @@ -199,6 +208,7 @@ public class InterceptorData { if (model != null) { final InterceptorData data = new InterceptorData(clazz); data.aroundInvoke.addAll(model.getAroundInvoke()); + data.aroundConstruct.addAll(model.getAroundConstruct()); data.postConstruct.addAll(model.getPostConstruct()); data.preDestroy.addAll(model.getPreDestroy()); data.postActivate.addAll(model.getPostActivate()); @@ -214,6 +224,7 @@ public class InterceptorData { final InterceptorData data = new InterceptorData(clazz); add(finder, data.aroundInvoke, AroundInvoke.class); + add(finder, data.aroundConstruct, AroundConstruct.class); add(finder, data.postConstruct, PostConstruct.class); add(finder, data.preDestroy, PreDestroy.class); add(finder, data.postActivate, PostActivate.class); diff --git a/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java b/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java index ec6654a8c7..83107c7d11 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/monitoring/StatsInterceptor.java @@ -17,6 +17,7 @@ package org.apache.openejb.monitoring; +import jakarta.interceptor.AroundConstruct; import org.apache.openejb.api.Monitor; import org.apache.openejb.core.interceptor.InterceptorData; import org.apache.openejb.loader.SystemInstance; @@ -102,6 +103,19 @@ public class StatsInterceptor { return record(invocationContext, null); } + public Method AroundConstruct() throws NoSuchMethodException { + return this.getClass().getMethod("AroundConstruct"); + } + + @AroundConstruct + public void AroundConstruct(final InvocationContext invocationContext) throws Exception { + final long start = System.nanoTime(); + record(invocationContext, AroundConstruct()); + final long end = System.nanoTime(); + Logger.getInstance(LogCategory.MONITORING, "org.apache.openejb.monitoring") + .debug("instance.creating", invocationContext.getTarget().getClass().getName(), end - start); + } + public Method PostConstruct() throws NoSuchMethodException { return this.getClass().getMethod("PostConstruct"); } diff --git a/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulInterceptorTest.java b/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulInterceptorTest.java index 0def17e59d..01c0a8210e 100644 --- a/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulInterceptorTest.java +++ b/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulInterceptorTest.java @@ -16,6 +16,7 @@ */ package org.apache.openejb.core.stateful; +import jakarta.interceptor.AroundConstruct; import junit.framework.TestCase; import org.apache.openejb.OpenEJB; import org.apache.openejb.assembler.classic.Assembler; @@ -76,6 +77,7 @@ public class StatefulInterceptorTest extends TestCase { assertEquals(3, ejbJar.interceptors.size()); assertEquals(1, ejbJar.interceptors.get(0).aroundInvoke.size()); + assertEquals(1, ejbJar.interceptors.get(0).aroundConstruct.size()); assertEquals(1, ejbJar.interceptors.get(0).postConstruct.size()); assertEquals(3, ejbJar.interceptorBindings.size()); @@ -117,7 +119,13 @@ public class StatefulInterceptorTest extends TestCase { assertEquals(join("\n", expected), join("\n", calls)); } - public static enum Call { + public enum Call { + Default_AroundConstruct_BEFORE, + Class_AroundConstruct_BEFORE, + Bean_AroundConstruct, + Class_AroundConstruct_AFTER, + Default_AroundConstruct_AFTER, + Default_PostConstruct_BEFORE, Class_PostConstruct_BEFORE, Bean_PostConstruct, @@ -161,6 +169,10 @@ public class StatefulInterceptorTest extends TestCase { public static class TargetBean implements Target { + public TargetBean() { + calls.add(Call.Bean_AroundConstruct); + } + @PostConstruct public void construct() { calls.add(Call.Bean_PostConstruct); @@ -232,6 +244,14 @@ public class StatefulInterceptorTest extends TestCase { calls.add(Call.Class_PostConstruct_AFTER); } + @AroundConstruct + public void aroundConstruct(final InvocationContext context) throws Exception { + calls.add(Call.Class_AroundConstruct_BEFORE); + context.proceed(); + calls.add(Call.Class_AroundConstruct_AFTER); + } + + @AroundInvoke public Object invoke(final InvocationContext context) throws Exception { calls.add(Call.Class_Invoke_BEFORE); @@ -250,6 +270,13 @@ public class StatefulInterceptorTest extends TestCase { calls.add(Call.Default_PostConstruct_AFTER); } + @AroundConstruct + public void aroundConstruct(final InvocationContext context) throws Exception { + calls.add(Call.Default_AroundConstruct_BEFORE); + context.proceed(); + calls.add(Call.Default_AroundConstruct_AFTER); + } + @AroundInvoke public Object invoke(final InvocationContext context) throws Exception { calls.add(Call.Default_Invoke_BEFORE); diff --git a/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java b/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java index 7fa68f3218..506ee5b745 100644 --- a/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java +++ b/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java @@ -118,6 +118,8 @@ public class Interceptor implements JndiConsumer, Session { protected KeyedCollection<String, JMSConnectionFactory> jmsConnectionFactories; @XmlElement(name = "jms-destination") protected KeyedCollection<String, JMSDestination> jmsDestinations; + @XmlElement(name = "around-construct", required = true) + protected List<LifecycleCallback> aroundConstruct; @XmlElement(name = "post-construct", required = true) protected List<LifecycleCallback> postConstruct; @XmlElement(name = "pre-destroy", required = true) @@ -337,6 +339,13 @@ public class Interceptor implements JndiConsumer, Session { return this.dataSource.toMap(); } + public List<LifecycleCallback> getAroundConstruct() { + if (aroundConstruct == null) { + aroundConstruct = new ArrayList<LifecycleCallback>(); + } + return this.aroundConstruct; + } + public List<LifecycleCallback> getPostConstruct() { if (postConstruct == null) { postConstruct = new ArrayList<LifecycleCallback>();