This is an automated email from the ASF dual-hosted git repository. rmannibucau pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/openwebbeans.git
The following commit(s) were added to refs/heads/master by this push: new d93a124 [OWB-1353][OWB-1354] adding ActivateRequestContextInterceptorBean and ensure lifecycle methods dont trigger unexpected interceptors d93a124 is described below commit d93a1248e079f083dc7e7343c7c0c5474cceb35c Author: Romain Manni-Bucau <rmannibu...@gmail.com> AuthorDate: Thu Nov 12 10:50:19 2020 +0100 [OWB-1353][OWB-1354] adding ActivateRequestContextInterceptorBean and ensure lifecycle methods dont trigger unexpected interceptors --- .../org/apache/webbeans/config/BeansDeployer.java | 7 +- .../ActivateRequestContextInterceptorBean.java | 167 +++++++++++++++++++++ .../intercept/InterceptorResolutionService.java | 20 ++- .../webbeans/intercept/InterceptorsManager.java | 4 +- .../webbeans/portable/InjectionTargetImpl.java | 7 +- .../org/apache/webbeans/util/WebBeansUtil.java | 10 ++ .../ActivateRequestContextInterceptorBeanTest.java | 78 ++++++++++ 7 files changed, 285 insertions(+), 8 deletions(-) diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java b/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java index aec5393..20489b1 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java @@ -43,6 +43,7 @@ import org.apache.webbeans.container.AnnotatedTypeWrapper; import org.apache.webbeans.container.BeanManagerImpl; import org.apache.webbeans.container.InjectableBeanManager; import org.apache.webbeans.container.InjectionResolver; +import org.apache.webbeans.context.control.ActivateRequestContextInterceptorBean; import org.apache.webbeans.corespi.se.DefaultJndiService; import org.apache.webbeans.decorator.DecoratorsManager; import org.apache.webbeans.deployment.StereoTypeManager; @@ -228,6 +229,10 @@ public class BeansDeployer webBeansContext.getBeanManagerImpl().addInternalBean(webBeansContext.getWebBeansUtil().getManagerBean()); // Register built-in RequestContextController webBeansContext.getBeanManagerImpl().addInternalBean(webBeansContext.getWebBeansUtil().getRequestContextControllerBean()); + webBeansContext.getInterceptorsManager().addCdiInterceptor(webBeansContext.getWebBeansUtil().getRequestContextInterceptorBean()); + webBeansContext.getInterceptorsManager().addPriorityClazzInterceptor( + ActivateRequestContextInterceptorBean.InterceptorClass.class, + javax.interceptor.Interceptor.Priority.PLATFORM_BEFORE + 100); //Fire Event fireBeforeBeanDiscoveryEvent(); @@ -618,7 +623,7 @@ public class BeansDeployer if (priority != null) { Class<?> javaClass = annotatedType.getJavaClass(); - interceptorsManager.addPriorityClazzInterceptor(javaClass, priority); + interceptorsManager.addPriorityClazzInterceptor(javaClass, priority.value()); } } if (annotatedType.getAnnotation(javax.decorator.Decorator.class) != null) diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/context/control/ActivateRequestContextInterceptorBean.java b/webbeans-impl/src/main/java/org/apache/webbeans/context/control/ActivateRequestContextInterceptorBean.java new file mode 100644 index 0000000..093d844 --- /dev/null +++ b/webbeans-impl/src/main/java/org/apache/webbeans/context/control/ActivateRequestContextInterceptorBean.java @@ -0,0 +1,167 @@ +/* + * 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. + */ + +package org.apache.webbeans.context.control; + +import org.apache.webbeans.annotation.EmptyAnnotationLiteral; +import org.apache.webbeans.config.WebBeansContext; +import org.apache.webbeans.util.AnnotationUtil; + +import javax.enterprise.context.Dependent; +import javax.enterprise.context.control.ActivateRequestContext; +import javax.enterprise.context.control.RequestContextController; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.InjectionPoint; +import javax.enterprise.inject.spi.InterceptionType; +import javax.enterprise.inject.spi.Interceptor; +import javax.interceptor.InvocationContext; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Set; + +import static java.util.Collections.emptySet; +import static java.util.Collections.singleton; + +public class ActivateRequestContextInterceptorBean + implements Interceptor<ActivateRequestContextInterceptorBean.InterceptorClass>, Serializable +{ + private static final Set<Annotation> BINDING = singleton(new ActivateRequestContextLiteral()); + private static final Set<Type> TYPES = singleton(Object.class); + private static final InterceptorClass INSTANCE = new InterceptorClass(); + + private final WebBeansContext webBeansContext; + private transient RequestContextController contextController; + + public ActivateRequestContextInterceptorBean(final WebBeansContext webBeansContext) + { + this.webBeansContext = webBeansContext; + this.contextController = new OwbRequestContextController(webBeansContext); + } + + @Override + public Set<Annotation> getInterceptorBindings() + { + return BINDING; + } + + @Override + public boolean intercepts(final InterceptionType type) + { + return true; + } + + @Override + public Object intercept(final InterceptionType type, final InterceptorClass instance, + final InvocationContext ctx) throws Exception + { + if (contextController == null) // synchro is not needed since the instance is backed by contextsservice + { + contextController = new OwbRequestContextController(webBeansContext); + } + final boolean activated = contextController.activate(); + try + { + return ctx.proceed(); + } + finally + { + if (activated) + { + contextController.deactivate(); + } + } + } + + @Override + public InterceptorClass create(final CreationalContext<InterceptorClass> context) + { + return INSTANCE; + } + + @Override + public void destroy(final InterceptorClass instance, final CreationalContext<InterceptorClass> context) + { + // no-op + } + + @Override + public Set<InjectionPoint> getInjectionPoints() + { + return emptySet(); + } + + @Override + public Class<?> getBeanClass() + { + return InterceptorClass.class; + } + + @Override + public boolean isNullable() + { + return false; + } + + @Override + public Set<Type> getTypes() + { + return TYPES; + } + + @Override + public Set<Annotation> getQualifiers() + { + return AnnotationUtil.DEFAULT_AND_ANY_ANNOTATION_SET; + } + + @Override + public Class<? extends Annotation> getScope() + { + return Dependent.class; + } + + @Override + public String getName() + { + return null; + } + + @Override + public Set<Class<? extends Annotation>> getStereotypes() + { + return emptySet(); + } + + @Override + public boolean isAlternative() + { + return false; + } + + public static class ActivateRequestContextLiteral + extends EmptyAnnotationLiteral<ActivateRequestContext> + implements ActivateRequestContext + { + } + + public static class InterceptorClass implements Serializable + { + } +} diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorResolutionService.java b/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorResolutionService.java index fee04fd..9a02b7c 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorResolutionService.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorResolutionService.java @@ -142,6 +142,9 @@ public class InterceptorResolutionService Map<Method, BusinessMethodInterceptorInfo> businessMethodInterceptorInfos = new HashMap<>(); Map<Constructor<?>, BusinessMethodInterceptorInfo> constructorInterceptorInfos = new HashMap<>(); + List<Interceptor<?>> classCdiInterceptors = new ArrayList<>(allUsedCdiInterceptors); + classCdiInterceptors.sort(new InterceptorComparator(webBeansContext)); + List<Method> nonInterceptedMethods = new ArrayList<>(); SelfInterceptorBean<T> selfInterceptorBean = resolveSelfInterceptorBean(annotatedType); @@ -245,7 +248,8 @@ public class InterceptorResolutionService cdiInterceptors, cdiConstructorInterceptors, selfInterceptorBean, constructorInterceptorInfos, businessMethodInterceptorInfos, - nonInterceptedMethods, lifecycleMethodInterceptorInfos); + nonInterceptedMethods, lifecycleMethodInterceptorInfos, + classCdiInterceptors); } /** @@ -877,11 +881,13 @@ public class InterceptorResolutionService Map<Constructor<?>, BusinessMethodInterceptorInfo> constructorInterceptorInfos, Map<Method, BusinessMethodInterceptorInfo> businessMethodsInfo, List<Method> nonInterceptedMethods, - Map<InterceptionType, LifecycleMethodInfo> lifecycleMethodInterceptorInfos) + Map<InterceptionType, LifecycleMethodInfo> lifecycleMethodInterceptorInfos, + List<Interceptor<?>> classCdiInterceptors) { this.decorators = decorators; this.ejbInterceptors = ejbInterceptors; this.cdiInterceptors = cdiInterceptors; + this.classCdiInterceptors = classCdiInterceptors; this.constructorCdiInterceptors = constructorCdiInterceptors; this.selfInterceptorBean = selfInterceptorBean; this.businessMethodsInfo = businessMethodsInfo; @@ -903,6 +909,11 @@ public class InterceptorResolutionService */ private List<Interceptor<?>> cdiInterceptors; + /** + * Class only interceptors (for lifecycle methods). + */ + private List<Interceptor<?>> classCdiInterceptors; + private final List<Interceptor<?>> constructorCdiInterceptors; /** @@ -940,6 +951,11 @@ public class InterceptorResolutionService return decorators; } + public List<Interceptor<?>> getClassCdiInterceptors() + { + return classCdiInterceptors; + } + public LinkedHashSet<Interceptor<?>> getEjbInterceptors() { return ejbInterceptors; diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorsManager.java b/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorsManager.java index 1428cb3..15c7ffe 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorsManager.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/intercept/InterceptorsManager.java @@ -40,8 +40,6 @@ import org.apache.webbeans.component.creation.BeanAttributesBuilder; import org.apache.webbeans.component.creation.EjbInterceptorBeanBuilder; import org.apache.webbeans.config.WebBeansContext; import org.apache.webbeans.container.BeanManagerImpl; -import javax.annotation.Priority; - import org.apache.webbeans.exception.WebBeansDeploymentException; import org.apache.webbeans.util.AnnotationUtil; import org.apache.webbeans.util.Asserts; @@ -359,7 +357,7 @@ public class InterceptorsManager return priorityInterceptors.getSorted(); } - public void addPriorityClazzInterceptor(Class<?> javaClass, Priority priority) + public void addPriorityClazzInterceptor(Class<?> javaClass, int priority) { priorityInterceptors.add(javaClass, priority); } diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/portable/InjectionTargetImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/portable/InjectionTargetImpl.java index 0134846..e24d968 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/portable/InjectionTargetImpl.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/portable/InjectionTargetImpl.java @@ -132,10 +132,13 @@ public class InjectionTargetImpl<T> extends AbstractProducer<T> implements Injec BeanInterceptorInfo interceptorInfo = getInterceptorInfo(); postConstructInterceptors - = getLifecycleInterceptors(interceptorInfo.getEjbInterceptors(), interceptorInfo.getCdiInterceptors(), InterceptionType.POST_CONSTRUCT); + = getLifecycleInterceptors(interceptorInfo.getEjbInterceptors(), interceptorInfo.getClassCdiInterceptors(), InterceptionType.POST_CONSTRUCT); preDestroyInterceptors - = getLifecycleInterceptors(interceptorInfo.getEjbInterceptors(), interceptorInfo.getCdiInterceptors(), InterceptionType.PRE_DESTROY); + = getLifecycleInterceptors(interceptorInfo.getEjbInterceptors(), interceptorInfo.getClassCdiInterceptors(), InterceptionType.PRE_DESTROY); + + // no more needed + interceptorInfo.getClassCdiInterceptors().clear(); InterceptorResolutionService.BusinessMethodInterceptorInfo constructorInterceptorInfo = interceptorInfo.getConstructorInterceptorInfos().get(getConstructor().getJavaMember()); diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java b/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java index 2c14c6b..2ddeead 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/util/WebBeansUtil.java @@ -55,6 +55,7 @@ import org.apache.webbeans.config.OwbWildcardTypeImpl; import org.apache.webbeans.config.WebBeansContext; import org.apache.webbeans.container.AnnotatedTypeWrapper; import org.apache.webbeans.container.InjectionResolver; +import org.apache.webbeans.context.control.ActivateRequestContextInterceptorBean; import org.apache.webbeans.context.control.RequestContextControllerBean; import org.apache.webbeans.exception.WebBeansConfigurationException; @@ -495,6 +496,15 @@ public final class WebBeansUtil } /** + * Creates a new bean for Request Context Interceptor. + * @return new request context interceptor bean instance + */ + public Interceptor<?> getRequestContextInterceptorBean() + { + return new ActivateRequestContextInterceptorBean(webBeansContext); + } + + /** * Creates a new instance bean. * @return new instance bean */ diff --git a/webbeans-impl/src/test/java/org/apache/webbeans/context/control/ActivateRequestContextInterceptorBeanTest.java b/webbeans-impl/src/test/java/org/apache/webbeans/context/control/ActivateRequestContextInterceptorBeanTest.java new file mode 100644 index 0000000..813bf15 --- /dev/null +++ b/webbeans-impl/src/test/java/org/apache/webbeans/context/control/ActivateRequestContextInterceptorBeanTest.java @@ -0,0 +1,78 @@ +/* + * 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. + */ +package org.apache.webbeans.context.control; + +import org.apache.webbeans.test.AbstractUnitTest; +import org.junit.Test; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.ContextNotActiveException; +import javax.enterprise.context.RequestScoped; +import javax.enterprise.context.control.ActivateRequestContext; +import javax.enterprise.inject.spi.BeanManager; +import javax.inject.Inject; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ActivateRequestContextInterceptorBeanTest extends AbstractUnitTest +{ + @Test + public void autoStartRequestScope() + { + startContainer(Service.class); + final Service service = getInstance(Service.class); + getWebBeansContext().getContextsService().endContext(RequestScoped.class, null); + assertFalse(service.isStarted()); + assertTrue(service.isStartedWithInterceptor()); + assertFalse(service.isStarted()); + } + + @ApplicationScoped + public static class Service + { + @Inject + private BeanManager beanManager; + + @PostConstruct + private void postConstruct() + { + assertFalse(isStarted()); + } + + @ActivateRequestContext + public boolean isStartedWithInterceptor() + { + return isStarted(); + } + + public boolean isStarted() + { + try + { + return beanManager.getContext(RequestScoped.class).isActive(); + } + catch (final ContextNotActiveException cnae) + { + return false; + } + } + } +}