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 50a9746 OWB-1316 make event bus faster when using Event class 50a9746 is described below commit 50a97460d3e824f298c52f98195a7d7ea5ac52af Author: Romain Manni-Bucau <rmannibu...@apache.org> AuthorDate: Wed Mar 11 16:09:26 2020 +0100 OWB-1316 make event bus faster when using Event class --- .../webbeans/annotation/AnnotationManager.java | 1 + .../apache/webbeans/config/WebBeansContext.java | 12 ++ .../webbeans/context/AbstractContextsService.java | 19 ++ .../webbeans/corespi/se/BaseSeContextsService.java | 33 +++- .../java/org/apache/webbeans/event/EventImpl.java | 174 ++++++++++++++++- .../apache/webbeans/event/NotificationManager.java | 215 ++++++++++++--------- .../apache/webbeans/event/ObserverMethodImpl.java | 43 +++-- .../webbeans/web/context/WebContextsService.java | 17 -- 8 files changed, 379 insertions(+), 135 deletions(-) diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java index 771be4b..24033f4 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/annotation/AnnotationManager.java @@ -417,6 +417,7 @@ public final class AnnotationManager { // performance hack to avoid Set creation checkQualifierConditions(qualifierAnnots[0]); + return; } Set<Annotation> annSet = ArrayUtil.asSet(qualifierAnnots); diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java b/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java index 848162f..c12eff6 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/config/WebBeansContext.java @@ -66,6 +66,7 @@ import org.apache.webbeans.spi.ConversationService; import org.apache.webbeans.spi.LoaderService; import org.apache.webbeans.spi.ScannerService; import org.apache.webbeans.spi.SecurityService; +import org.apache.webbeans.spi.TransactionService; import org.apache.webbeans.spi.plugins.OpenWebBeansPlugin; import org.apache.webbeans.util.ClassUtil; import org.apache.webbeans.util.WebBeansUtil; @@ -114,6 +115,7 @@ public class WebBeansContext private ConversationService conversationService; private final ApplicationBoundaryService applicationBoundaryService; private final NotificationManager notificationManager; + private TransactionService transactionService; public WebBeansContext() @@ -342,6 +344,16 @@ public class WebBeansContext return subclassProxyFactory; } + public TransactionService getTransactionService() // used in event bus so ensure it is a plain getter at runtime + { + if (transactionService == null) + { + // lazy init + transactionService = getService(TransactionService.class); + } + return transactionService; + } + public ScannerService getScannerService() { if (scannerService == null) diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java b/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java index a1f2033..43ec3c0 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/context/AbstractContextsService.java @@ -26,9 +26,13 @@ import javax.enterprise.context.ContextException; import javax.enterprise.context.SessionScoped; import javax.enterprise.context.spi.Context; +import org.apache.webbeans.annotation.BeforeDestroyedLiteral; +import org.apache.webbeans.annotation.DestroyedLiteral; +import org.apache.webbeans.annotation.InitializedLiteral; import org.apache.webbeans.config.WebBeansContext; import org.apache.webbeans.conversation.ConversationImpl; import org.apache.webbeans.conversation.ConversationManager; +import org.apache.webbeans.event.NotificationManager; import org.apache.webbeans.spi.ContextsService; public abstract class AbstractContextsService implements ContextsService @@ -37,6 +41,7 @@ public abstract class AbstractContextsService implements ContextsService protected boolean supportsConversation; + protected Boolean fireRequestLifecycleEvents; protected AbstractContextsService(WebBeansContext webBeansContext) { @@ -137,4 +142,18 @@ public abstract class AbstractContextsService implements ContextsService { return supportsConversation; } + + protected boolean shouldFireRequestLifecycleEvents() + { + if (fireRequestLifecycleEvents == null) + { + NotificationManager notificationManager = webBeansContext.getNotificationManager(); + fireRequestLifecycleEvents + = notificationManager.hasContextLifecycleObserver(InitializedLiteral.INSTANCE_REQUEST_SCOPED) || + notificationManager.hasContextLifecycleObserver(BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED) || + notificationManager.hasContextLifecycleObserver(DestroyedLiteral.INSTANCE_REQUEST_SCOPED) ; + } + + return fireRequestLifecycleEvents; + } } diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java b/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java index 11ea0db..9bd65cb 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/corespi/se/BaseSeContextsService.java @@ -332,8 +332,11 @@ public abstract class BaseSeContextsService extends AbstractContextsService ctx.setActive(true); requestContext.set(ctx); - webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent( - new Object(), InitializedLiteral.INSTANCE_REQUEST_SCOPED); + if (shouldFireRequestLifecycleEvents()) + { + webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent( + ctx, InitializedLiteral.INSTANCE_REQUEST_SCOPED); + } } @@ -395,18 +398,28 @@ public abstract class BaseSeContextsService extends AbstractContextsService conversationContext.remove(); } - webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent( - new Object(), BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED); - if(requestContext.get() != null) + + if (shouldFireRequestLifecycleEvents()) { - requestContext.get().destroy(); + webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent( + new Object(), BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED); } - requestContext.set(null); - requestContext.remove(); + final RequestContext ctx = BaseSeContextsService.requestContext.get(); + if (ctx != null) + { + ctx.destroy(); + } + + BaseSeContextsService.requestContext.set(null); + BaseSeContextsService.requestContext.remove(); RequestScopedBeanInterceptorHandler.removeThreadLocals(); - webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent( - new Object(), DestroyedLiteral.INSTANCE_REQUEST_SCOPED); + + if (shouldFireRequestLifecycleEvents()) + { + webBeansContext.getBeanManagerImpl().fireContextLifecyleEvent( + ctx, DestroyedLiteral.INSTANCE_REQUEST_SCOPED); + } } diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java index cbe93e0..5f7b71f 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/event/EventImpl.java @@ -22,12 +22,19 @@ import java.io.IOException; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.enterprise.event.Event; import javax.enterprise.event.NotificationOptions; import javax.enterprise.inject.spi.EventMetadata; +import javax.enterprise.inject.spi.ObserverMethod; import javax.enterprise.util.TypeLiteral; import org.apache.webbeans.config.WebBeansContext; @@ -47,6 +54,13 @@ public class EventImpl<T> implements Event<T>, Serializable private transient WebBeansContext webBeansContext; + // cache for metadata != this.metadata + private volatile transient ConcurrentMap<ObserverCacheKey, List<ObserverMethod<? super Object>>> observers; + private volatile transient ConcurrentMap<ObserverCacheKey, List<ObserverMethod<? super Object>>> asyncObservers; + // cache for metadata == this.metadata (fast path) + private volatile transient List<ObserverMethod<? super Object>> defaultMetadataObservers; + private volatile transient List<ObserverMethod<? super Object>> defaultMetadataAsyncObservers; + /** * Creates a new event. * @@ -57,6 +71,12 @@ public class EventImpl<T> implements Event<T>, Serializable Asserts.assertNotNull(metadata, "event metadata"); this.metadata = wrapMetadata(metadata); this.webBeansContext = webBeansContext; + // earger validation to bypass it at runtime + this.webBeansContext.getWebBeansUtil().validEventType(metadata.getType(), metadata.getType()); + if (webBeansContext.getWebBeansUtil().isContainerEventType(this.metadata.validatedType())) + { + throw new IllegalArgumentException("Firing container events is forbidden"); + } } private EventMetadataImpl wrapMetadata(EventMetadata metadata) @@ -79,8 +99,16 @@ public class EventImpl<T> implements Event<T>, Serializable public void fire(T event) { Type eventType = event.getClass(); - webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType()); - webBeansContext.getBeanManagerImpl().fireEvent(event, metadata.select(eventType), false); + if (metadata.validatedType() == eventType) + { + // already validated so don't recall validEventType() + doFireSyncEvent(event, metadata); + } + else + { + webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType()); + doFireSyncEvent(event, metadata.select(eventType)); + } } @Override @@ -93,9 +121,13 @@ public class EventImpl<T> implements Event<T>, Serializable public <U extends T> CompletionStage<U> fireAsync(U event, NotificationOptions notificationOptions) { Type eventType = event.getClass(); - webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType()); - return webBeansContext.getNotificationManager().fireEvent(event, metadata.select(eventType), false, - notificationOptions); + if (eventType != metadata.validatedType()) + { + webBeansContext.getWebBeansUtil().validEventType(eventType.getClass(), metadata.getType()); + return webBeansContext.getNotificationManager() + .fireEvent(event, metadata.select(eventType), false, notificationOptions); + } + return doFireAsyncEvent(event, metadata, notificationOptions); } /** @@ -135,4 +167,136 @@ public class EventImpl<T> implements Event<T>, Serializable { return metadata; } + + private void doFireSyncEvent(T event, EventMetadataImpl metadata) + { + final NotificationManager notificationManager = webBeansContext.getNotificationManager(); + List<ObserverMethod<? super Object>> observerMethods; + if (metadata == this.metadata) // no validation of isContainerEventType, already done + { + if (defaultMetadataObservers == null) + { + final List<ObserverMethod<? super Object>> tmp = new ArrayList<>( // faster than LinkedList + notificationManager.resolveObservers(event, metadata, false)); + notificationManager.prepareObserverListForFire(false, false, tmp); + this.defaultMetadataObservers = tmp; + } + observerMethods = defaultMetadataObservers; + } + else + { + if (webBeansContext.getWebBeansUtil().isContainerEventType(event)) + { + throw new IllegalArgumentException("Firing container events is forbidden"); + } + + if (observers == null) + { + synchronized (this) + { + if (observers == null) + { + observers = new ConcurrentHashMap<>(); + } + } + } + final ObserverCacheKey key = new ObserverCacheKey( + event.getClass(), metadata.validatedType(), metadata.getQualifiers()); + observerMethods = observers.get(key); + if (observerMethods == null) + { + observerMethods = new ArrayList<>( // faster than LinkedList + notificationManager.resolveObservers(event, metadata, false)); + notificationManager.prepareObserverListForFire(false, false, observerMethods); + this.observers.putIfAbsent(key, observerMethods); + } + } + notificationManager.doFireSync(new EventContextImpl<>(event, metadata), false, observerMethods); + } + + private <U extends T> CompletionStage<U> doFireAsyncEvent(T event, EventMetadataImpl metadata, NotificationOptions options) + { + final NotificationManager notificationManager = webBeansContext.getNotificationManager(); + List<ObserverMethod<? super Object>> observerMethods; + if (metadata == this.metadata) // no validation of isContainerEventType, already done + { + if (defaultMetadataAsyncObservers == null) + { + final List<ObserverMethod<? super Object>> tmp = new ArrayList<>( // faster than LinkedList + notificationManager.resolveObservers(event, metadata, false)); + notificationManager.prepareObserverListForFire(false, true, tmp); + this.defaultMetadataAsyncObservers = tmp; + } + observerMethods = defaultMetadataAsyncObservers; + } + else + { + if (webBeansContext.getWebBeansUtil().isContainerEventType(event)) + { + throw new IllegalArgumentException("Firing container events is forbidden"); + } + + if (asyncObservers == null) + { + synchronized (this) + { + if (asyncObservers == null) + { + asyncObservers = new ConcurrentHashMap<>(); + } + } + } + final ObserverCacheKey key = new ObserverCacheKey( + event.getClass(), metadata.validatedType(), metadata.getQualifiers()); + observerMethods = asyncObservers.get(key); + if (observerMethods == null) + { + observerMethods = new ArrayList<>( // faster than LinkedList + notificationManager.resolveObservers(event, metadata, false)); + notificationManager.prepareObserverListForFire(false, true, observerMethods); + this.asyncObservers.putIfAbsent(key, observerMethods); + } + } + return notificationManager.doFireAsync( + new EventContextImpl<>(event, metadata), false, options, observerMethods); + } + + private static class ObserverCacheKey + { + private final Class<?> clazz; + private final Type type; + private final Collection<Annotation> qualifiers; + private final int hash; + + private ObserverCacheKey(Class<?> clazz, Type type, Collection<Annotation> qualifiers) + { + this.clazz = clazz; + this.type = type; + this.qualifiers = qualifiers; + this.hash = Objects.hash(clazz, type, qualifiers); + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + ObserverCacheKey that = ObserverCacheKey.class.cast(o); + return Objects.equals(clazz, that.clazz) && + Objects.equals(type, that.type) && + Objects.equals(qualifiers, that.qualifiers); + } + + @Override + public int hashCode() + { + return hash; + } + } } diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java b/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java index c7f02b5..c7703c7 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/event/NotificationManager.java @@ -31,8 +31,6 @@ import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -59,6 +57,7 @@ import javax.enterprise.inject.spi.AnnotatedField; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedParameter; import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.EventContext; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ObserverMethod; import javax.enterprise.inject.spi.ProcessAnnotatedType; @@ -75,6 +74,7 @@ import org.apache.webbeans.portable.events.generics.GProcessObserverMethod; import org.apache.webbeans.portable.events.generics.GenericBeanEvent; import org.apache.webbeans.portable.events.generics.GenericProducerObserverEvent; import org.apache.webbeans.portable.events.generics.TwoParametersGenericBeanEvent; +import org.apache.webbeans.spi.ContextsService; import org.apache.webbeans.spi.TransactionService; import org.apache.webbeans.util.AnnotationUtil; import org.apache.webbeans.util.Asserts; @@ -195,9 +195,8 @@ public final class NotificationManager public <T> Collection<ObserverMethod<? super T>> resolveObservers(T event, EventMetadataImpl metadata, boolean isLifecycleEvent) { Type eventType = metadata.validatedType(); - Collection<ObserverMethod<? super T>> observersMethods = filterByType(event, eventType, isLifecycleEvent); - - observersMethods = filterByQualifiers(observersMethods, metadata.getQualifiers()); + Collection<ObserverMethod<? super T>> observersMethods = filterByQualifiers( + filterByType(event, eventType, isLifecycleEvent), metadata.getQualifiers()); if (isLifecycleEvent && event instanceof ProcessAnnotatedType) { @@ -641,124 +640,167 @@ public final class NotificationManager * Fire the given event * @param notificationOptions if {@code null} then this is a synchronous event. Otherwise fireAsync */ - public <T> CompletionStage<T> fireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent, NotificationOptions notificationOptions) + public <T> CompletionStage<T> fireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent, + NotificationOptions notificationOptions) { boolean async = notificationOptions != null; - if (!isLifecycleEvent && webBeansContext.getWebBeansUtil().isContainerEventType(event)) { throw new IllegalArgumentException("Firing container events is forbidden"); } + return doFireEvent( + event, metadata, isLifecycleEvent, notificationOptions, async, + new ArrayList<>(resolveObservers(event, metadata, isLifecycleEvent))); - LinkedList<ObserverMethod<? super Object>> observerMethods = new LinkedList<>(resolveObservers(event, metadata, isLifecycleEvent)); + } - // async doesn't apply to Extension lifecycle events - if (!isLifecycleEvent) + public <T> CompletionStage<T> doFireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent, + NotificationOptions notificationOptions, boolean async, + List<ObserverMethod<? super Object>> observerMethods) + { + prepareObserverListForFire(isLifecycleEvent, async, observerMethods); + EventContextImpl<Object> context = new EventContextImpl<>(event, metadata); + if (async) { - // filter for all async or all synchronous observermethods - // oldschool and not Streams, because of performance and avoiding tons of temporary objects - Iterator<ObserverMethod<? super Object>> observerMethodIterator = observerMethods.iterator(); - while (observerMethodIterator.hasNext()) + return doFireAsync(context, isLifecycleEvent, notificationOptions, observerMethods); + } + doFireSync(context, isLifecycleEvent, observerMethods); + return null; + + } + + public <T> CompletionStage<T> doFireAsync(EventContext<?> context, + boolean isLifecycleEvent, NotificationOptions notificationOptions, + List<ObserverMethod<? super Object>> observerMethods) + { + List<CompletableFuture<Void>> completableFutures = new ArrayList<>(); + for (ObserverMethod<? super Object> observer : observerMethods) + { + try { - if (async != observerMethodIterator.next().isAsync()) + TransactionPhase phase = observer.getTransactionPhase(); + + if (phase == null || phase == TransactionPhase.IN_PROGRESS) { - observerMethodIterator.remove(); + completableFutures.add(invokeObserverMethodAsync(context, observer, notificationOptions)); } + else + { + throw new WebBeansConfigurationException("Async Observer Methods can only use TransactionPhase.IN_PROGRESS!"); + } + } + catch (WebBeansException e) + { + return onWebBeansException(context.getEvent(), isLifecycleEvent, e); + } + catch (RuntimeException e) + { + throw e; + } + catch (Exception e) + { + throw new WebBeansException(e); } } + return complete(completableFutures, (T) context.getEvent()); + } - // new in CDI-2.0: sort observers - if (observerMethods.size() > 1) + public void doFireSync(EventContext<?> context, boolean isLifecycleEvent, + List<ObserverMethod<? super Object>> observerMethods) + { + if (observerMethods.isEmpty()) { - observerMethods.sort(observerMethodComparator); + return; } - - List<CompletableFuture<Void>> completableFutures = async ? new ArrayList<>() : null; - + // synchronous case for (ObserverMethod<? super Object> observer : observerMethods) { try { - if (isLifecycleEvent && !Extension.class.isAssignableFrom(observer.getBeanClass())) - { - // we must not fire Extension Lifecycle events to beans which are no Extensions - continue; - } - TransactionPhase phase = observer.getTransactionPhase(); - - if(phase != null && phase != TransactionPhase.IN_PROGRESS) - { - if (async) - { - throw new WebBeansConfigurationException("Async Observer Methods can only use TransactionPhase.IN_PROGRESS!"); - } - TransactionService transactionService = webBeansContext.getService(TransactionService.class); - if(transactionService != null) - { - transactionService.registerTransactionSynchronization(phase, observer, event); - } - else - { - invokeObserverMethod(event, metadata, observer); - } + if (phase == null || phase != TransactionPhase.IN_PROGRESS) + { + invokeObserverMethod(context, observer); } else { - if (async) + TransactionService transactionService = webBeansContext.getTransactionService(); + if(transactionService != null) { - completableFutures.add(invokeObserverMethodAsync(event, metadata, observer, notificationOptions)); + transactionService.registerTransactionSynchronization(phase, observer, context.getEvent()); } else { - invokeObserverMethod(event, metadata, observer); + invokeObserverMethod(context, observer); } } } catch (WebBeansException e) { - Throwable exc = e.getCause(); - if(exc instanceof InvocationTargetException) - { - InvocationTargetException invt = (InvocationTargetException)exc; - exc = invt.getCause(); - } - - if (isLifecycleEvent) - { - if (event instanceof AfterDeploymentValidation) - { - throw new WebBeansDeploymentException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e); - } - else - { - throw new WebBeansConfigurationException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e); - } - } - - if (!RuntimeException.class.isAssignableFrom(exc.getClass())) - { - throw new ObserverException(WebBeansLoggerFacade.getTokenString(OWBLogConst.EXCEPT_0008) + event.getClass().getName(), e); - } - else - { - RuntimeException rte = (RuntimeException) exc; - throw rte; - } + onWebBeansException(context.getEvent(), isLifecycleEvent, e); } catch (RuntimeException e) { throw e; } - catch (Exception e) { throw new WebBeansException(e); } } + } + + public void prepareObserverListForFire(boolean isLifecycleEvent, boolean async, + List<ObserverMethod<? super Object>> observerMethods) + { + // async doesn't apply to Extension lifecycle events + if (!isLifecycleEvent) + { + // filter for all async or all synchronous observermethods + // oldschool and not Streams, because of performance and avoiding tons of temporary objects + observerMethods.removeIf(observerMethod -> async != observerMethod.isAsync()); + } + else + { + observerMethods.removeIf(observer -> !Extension.class.isAssignableFrom(observer.getBeanClass())); + } + + // new in CDI-2.0: sort observers + if (observerMethods.size() > 1) + { + observerMethods.sort(observerMethodComparator); + } + } + + private <T> CompletionStage<T> onWebBeansException(final Object event, final boolean isLifecycleEvent, + final WebBeansException e) + { + Throwable exc = e.getCause(); + if(exc instanceof InvocationTargetException) + { + InvocationTargetException invt = (InvocationTargetException)exc; + exc = invt.getCause(); + } + + if (isLifecycleEvent) + { + if (event instanceof AfterDeploymentValidation) + { + throw new WebBeansDeploymentException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e); + } + else + { + throw new WebBeansConfigurationException("Error while sending SystemEvent to a CDI Extension! " + event.toString(), e); + } + } - return async ? complete(completableFutures, (T) event) : null; + if (!RuntimeException.class.isAssignableFrom(exc.getClass())) + { + throw new ObserverException(WebBeansLoggerFacade.getTokenString(OWBLogConst.EXCEPT_0008) + event.getClass().getName(), e); + } + RuntimeException rte = (RuntimeException) exc; + throw rte; } private <T> CompletableFuture<T> complete(List<CompletableFuture<Void>> completableFutures, T event) @@ -780,8 +822,7 @@ public final class NotificationManager return future; } - private CompletableFuture invokeObserverMethodAsync(Object event, - EventMetadataImpl metadata, + private CompletableFuture invokeObserverMethodAsync(EventContext<?> context, ObserverMethod<? super Object> observer, NotificationOptions notificationOptions) { @@ -789,7 +830,7 @@ public final class NotificationManager CompletableFuture.runAsync(() -> { try { - runAsync(event, metadata, observer); + runAsync(context, observer); future.complete(null); } catch (WebBeansException wbe) @@ -800,23 +841,25 @@ public final class NotificationManager return future; } - private void runAsync(Object event, EventMetadataImpl metadata, ObserverMethod<? super Object> observer) + private void runAsync(EventContext<?> context, ObserverMethod<? super Object> observer) { //X TODO set up threads, requestcontext etc - webBeansContext.getContextsService().startContext(RequestScoped.class, null); + final ContextsService contextsService = webBeansContext.getContextsService(); + contextsService.getCurrentContext(RequestScoped.class); + contextsService.startContext(RequestScoped.class, null); try { - invokeObserverMethod(event, metadata, observer); + invokeObserverMethod(context, observer); } finally { - webBeansContext.getContextsService().endContext(RequestScoped.class, null); + contextsService.endContext(RequestScoped.class, null); } } - private <T> void invokeObserverMethod(T event, EventMetadataImpl metadata, ObserverMethod<?> observer) + private void invokeObserverMethod(EventContext context, ObserverMethod<?> observer) { - observer.notify(new EventContextImpl(event, metadata)); + observer.notify(context); } /** diff --git a/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java b/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java index d2fad9f..7061714 100644 --- a/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java +++ b/webbeans-impl/src/main/java/org/apache/webbeans/event/ObserverMethodImpl.java @@ -199,6 +199,11 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T> } checkObserverCondition(annotatedObservesParameter); + + if (!view.isAccessible()) + { + ownerBean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(view, true); + } } protected void checkObserverCondition(AnnotatedParameter<T> annotatedObservesParameter) @@ -278,22 +283,26 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T> ObserverParams[] obargs = null; try { - obargs = new ObserverParams[methodArgsMap.size()]; - obargs = methodArgsMap.toArray(obargs); - Object[] args = new Object[obargs.length]; - int i = 0; - for(ObserverParams param : obargs) + Object[] args; + if (methodArgsMap == null) + { + args = new Object[]{event}; + } + else { - args[i++] = param.instance; + args = new Object[methodArgsMap.size()]; + obargs = new ObserverParams[args.length]; + obargs = methodArgsMap.toArray(obargs); + int i = 0; + for (ObserverParams param : obargs) + { + args[i++] = param.instance; + } } //Static or not if (Modifier.isStatic(view.getModifiers())) { - if (!view.isAccessible()) - { - view.setAccessible(true); - } //Invoke Method view.invoke(null, args); } @@ -347,14 +356,9 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T> if (object != null) { - if (!view.isAccessible()) - { - ownerBean.getWebBeansContext().getSecurityService().doPrivilegedSetAccessible(view, true); - } - if (Modifier.isPrivate(view.getModifiers())) { - // since private methods cannot be intercepted, we have to unwrap anny possible proxy + // since private methods cannot be intercepted, we have to unwrap any possible proxy if (object instanceof OwbNormalScopeProxy) { object = getWebBeansContext().getInterceptorDecoratorProxyFactory().unwrapInstance(object); @@ -385,7 +389,7 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T> } //Destroy observer method dependent instances - if(methodArgsMap != null) + if(methodArgsMap != null && obargs != null) { for(ObserverParams param : obargs) { @@ -411,6 +415,11 @@ public class ObserverMethodImpl<T> implements OwbObserverMethod<T> */ protected List<ObserverParams> getMethodArguments(Object event, EventMetadata metadata) { + if (injectionPoints.isEmpty() && annotatedObservesParameter.getPosition() == 0) + { + return null; // special handling + } + List<ObserverParams> list = new ArrayList<>(); if (annotatedObservesParameter.getPosition() == 0) { diff --git a/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java b/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java index 0055c3a..135c867 100644 --- a/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java +++ b/webbeans-web/src/main/java/org/apache/webbeans/web/context/WebContextsService.java @@ -33,7 +33,6 @@ import org.apache.webbeans.context.SessionContext; import org.apache.webbeans.context.SingletonContext; import org.apache.webbeans.conversation.ConversationManager; import org.apache.webbeans.el.ELContextStore; -import org.apache.webbeans.event.NotificationManager; import org.apache.webbeans.intercept.SessionScopedBeanInterceptorHandler; import org.apache.webbeans.logger.WebBeansLoggerFacade; import org.apache.webbeans.intercept.RequestScopedBeanInterceptorHandler; @@ -99,8 +98,6 @@ public class WebContextsService extends AbstractContextsService protected Pattern eagerSessionPattern; - protected Boolean fireRequestLifecycleEvents; - /** * Creates a new instance. */ @@ -806,20 +803,6 @@ public class WebContextsService extends AbstractContextsService return conversationContext; } - protected boolean shouldFireRequestLifecycleEvents() - { - if (fireRequestLifecycleEvents == null) - { - NotificationManager notificationManager = webBeansContext.getNotificationManager(); - fireRequestLifecycleEvents - = notificationManager.hasContextLifecycleObserver(InitializedLiteral.INSTANCE_REQUEST_SCOPED) || - notificationManager.hasContextLifecycleObserver(BeforeDestroyedLiteral.INSTANCE_REQUEST_SCOPED) || - notificationManager.hasContextLifecycleObserver(DestroyedLiteral.INSTANCE_REQUEST_SCOPED) ; - } - - return fireRequestLifecycleEvents; - } - /** * Try to lazily start the sessionContext.