You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by rm...@apache.org on 2020/03/11 15:09:36 UTC
[openwebbeans] branch master updated: OWB-1316 make event bus
faster when using Event class
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 <rm...@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.