
org.apache.webbeans.event.NotificationManager Maven / Gradle / Ivy
/*
* 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.event;
import java.io.Closeable;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.NotificationOptions;
import javax.enterprise.event.ObserverException;
import javax.enterprise.event.TransactionPhase;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.AnnotatedCallable;
import javax.enterprise.inject.spi.AnnotatedConstructor;
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;
import javax.enterprise.inject.spi.ProcessBean;
import javax.enterprise.inject.spi.ProcessBeanAttributes;
import javax.enterprise.inject.spi.ProcessInjectionPoint;
import javax.enterprise.inject.spi.ProcessInjectionTarget;
import javax.enterprise.inject.spi.ProcessManagedBean;
import javax.enterprise.inject.spi.ProcessObserverMethod;
import javax.enterprise.inject.spi.ProcessProducer;
import javax.enterprise.inject.spi.ProcessProducerField;
import javax.enterprise.inject.spi.ProcessProducerMethod;
import javax.enterprise.inject.spi.ProcessSyntheticBean;
import javax.enterprise.inject.spi.ProcessSyntheticObserverMethod;
import org.apache.webbeans.component.AbstractOwbBean;
import org.apache.webbeans.config.OWBLogConst;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.exception.WebBeansConfigurationException;
import org.apache.webbeans.exception.WebBeansDeploymentException;
import org.apache.webbeans.exception.WebBeansException;
import org.apache.webbeans.logger.WebBeansLoggerFacade;
import org.apache.webbeans.portable.events.ProcessAnnotatedTypeImpl;
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;
import org.apache.webbeans.util.ClassUtil;
import org.apache.webbeans.util.GenericsUtil;
import org.apache.webbeans.util.WebBeansUtil;
import static java.util.Collections.emptyList;
import static java.util.concurrent.CompletableFuture.completedFuture;
import static java.util.stream.Collectors.toMap;
public class NotificationManager
{
private final Map>> observers = new ConcurrentHashMap<>();
private final WebBeansContext webBeansContext;
private final NotificationOptions defaultNotificationOptions;
/**
* Contains information whether certain Initialized and Destroyed events have observer methods.
*/
private final ConcurrentMap hasContextLifecycleEventObservers
= new ConcurrentHashMap<>();
/**
* List of ObserverMethods cached by their raw types.
*/
private final ConcurrentHashMap, Set>> observersByRawType
= new ConcurrentHashMap<>();
// this is actually faster than a lambda Comparator.comparingInt(ObserverMethod::getPriority)
private Comparator super ObserverMethod super Object>> observerMethodComparator
= new Comparator>()
{
@Override
public int compare(ObserverMethod super Object> o1, ObserverMethod super Object> o2)
{
return Integer.compare(o1.getPriority(), o2.getPriority());
}
};
// idea is to be able to skip O(n) events in favor of an algorithm closer to O(1) impl
// statistically, it is not rare to not use all these events so we enable to skip most of them
private Map>> processAnnotatedTypeObservers;
private Map>> processBeanAttributesObservers;
private Map>> processInjectionTargetObservers;
private Map>> processManagedBeanObservers;
private Map>> processBeanObservers;
private Map>> processInjectionPointObservers;
private Map>> processObserverMethodObservers;
private Map>> processProducerObservers;
private Map>> processProducerFieldObservers;
private Map>> processProducerMethodObservers;
private Map>> processSyntheticBeanObservers;
private Map>> processSyntheticObserverMethodObservers;
public NotificationManager(WebBeansContext webBeansContext)
{
this.webBeansContext = webBeansContext;
this.defaultNotificationOptions = NotificationOptions.ofExecutor(getDefaultExecutor());
}
private Executor getDefaultExecutor()
{
// here it would be nice to support to use a produced bean like @Named("openwebbeansCdiExecutor")
// instead of a direct spi
//
// logic is: if an Executor is registered as a spi use it, otherwise use JVM default one
Executor service = webBeansContext.getService(Executor.class);
return service != null ? service : new CloseableExecutor();
}
/**
* This methods needs to get called after the container got started.
* This is to avoid that events which already got fired during bootstrap in Extensions
* will get cached and events from beans thus get ignored.
*/
public void clearCaches()
{
observersByRawType.clear();
hasContextLifecycleEventObservers.clear();
processAnnotatedTypeObservers = null;
processBeanAttributesObservers = null;
processInjectionTargetObservers = null;
processManagedBeanObservers = null;
processBeanObservers = null;
processInjectionPointObservers = null;
processObserverMethodObservers = null;
processProducerObservers = null;
processProducerFieldObservers = null;
processProducerMethodObservers = null;
processSyntheticBeanObservers = null;
processSyntheticObserverMethodObservers = null;
}
/**
*
* @param lifecycleEvent e.g. {@link org.apache.webbeans.annotation.DestroyedLiteral#INSTANCE_REQUEST_SCOPED}
* @return whether the given Initialized or Destroyed event has observer methods.
*/
public boolean hasContextLifecycleObserver(Annotation lifecycleEvent)
{
Boolean hasObserver = hasContextLifecycleEventObservers.get(lifecycleEvent);
if (hasObserver == null)
{
hasObserver = Boolean.FALSE;
for (ObserverMethod> observerMethod : getObserverMethods())
{
if (observerMethod.getObservedQualifiers().contains(lifecycleEvent))
{
hasObserver = Boolean.TRUE;
break;
}
}
hasContextLifecycleEventObservers.putIfAbsent(lifecycleEvent, hasObserver);
}
return hasObserver;
}
public List> getObserverMethods()
{
List> observerMethods = new ArrayList<>();
for (Set> methods: observers.values())
{
for (ObserverMethod> method: methods)
{
observerMethods.add(method);
}
}
return observerMethods;
}
public void addObserver(ObserverMethod observer)
{
webBeansContext.getAnnotationManager().checkQualifierConditions(observer.getObservedQualifiers());
Set> set = observers.computeIfAbsent(observer.getObservedType(), k -> new HashSet<>());
set.add(observer);
}
public boolean hasProcessAnnotatedTypeObservers()
{
cacheIfNeeded(new ProcessAnnotatedTypeImpl<>(null, null));
return !processAnnotatedTypeObservers.isEmpty();
}
public Collection> resolveObservers(T event, EventMetadataImpl metadata, boolean isLifecycleEvent)
{
if (isLifecycleEvent) // goal here is to skip any resolution if not needed
{
Collection observerMethods = cacheIfNeeded(event);
if (observerMethods != null) // emptyList()
{
return observerMethods;
}
}
Type eventType = metadata.validatedType();
Collection> observersMethods = filterByQualifiers(
filterByType(event, eventType, isLifecycleEvent), metadata.getQualifiers());
if (isLifecycleEvent && event instanceof ProcessAnnotatedType)
{
observersMethods = filterByWithAnnotations(observersMethods, ((ProcessAnnotatedType) event).getAnnotatedType());
}
else if (!isLifecycleEvent && observersMethods.isEmpty())
{
//this check for the TCK is only needed if no observer was found
EventUtil.checkEventBindings(webBeansContext, metadata.getQualifiers());
EventUtil.checkQualifierImplementations(metadata.getQualifiers());
}
return observersMethods;
}
private Collection> cacheIfNeeded(final T event)
{
if (event instanceof ProcessAnnotatedType)
{
if (processAnnotatedTypeObservers == null)
{
processAnnotatedTypeObservers = findObservers(ProcessAnnotatedType.class);
}
if (processAnnotatedTypeObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessManagedBean)
{
if (processManagedBeanObservers == null)
{
processManagedBeanObservers = findObservers(ProcessManagedBean.class);
if (processBeanObservers == null)
{
processBeanObservers = findObservers(ProcessBean.class);
}
processBeanObservers.forEach((k, v) -> processManagedBeanObservers
.computeIfAbsent(k, it -> new HashSet<>())
.addAll(v));
}
if (processManagedBeanObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessProducerField)
{
if (processProducerFieldObservers == null)
{
processProducerFieldObservers = findObservers(ProcessProducerField.class);
if (processBeanObservers == null)
{
processBeanObservers = findObservers(ProcessBean.class);
}
processBeanObservers.forEach((k, v) -> processProducerFieldObservers
.computeIfAbsent(k, it -> new HashSet<>())
.addAll(v));
}
if (processProducerFieldObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessProducerMethod)
{
if (processProducerMethodObservers == null)
{
processProducerMethodObservers = findObservers(ProcessProducerMethod.class);
if (processBeanObservers == null)
{
processBeanObservers = findObservers(ProcessBean.class);
}
processBeanObservers.forEach((k, v) -> processProducerMethodObservers
.computeIfAbsent(k, it -> new HashSet<>())
.addAll(v));
}
if (processProducerMethodObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessSyntheticBean)
{
if (processSyntheticBeanObservers == null)
{
processSyntheticBeanObservers = findObservers(ProcessSyntheticBean.class);
if (processBeanObservers == null)
{
processBeanObservers = findObservers(ProcessBean.class);
}
processBeanObservers.forEach((k, v) -> processSyntheticBeanObservers
.computeIfAbsent(k, it -> new HashSet<>())
.addAll(v));
}
if (processSyntheticBeanObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessSyntheticObserverMethod)
{
if (processSyntheticObserverMethodObservers == null)
{
processSyntheticObserverMethodObservers = findObservers(ProcessSyntheticObserverMethod.class);
if (processObserverMethodObservers == null)
{
processObserverMethodObservers = findObservers(ProcessObserverMethod.class);
}
processObserverMethodObservers.forEach((k, v) -> processSyntheticObserverMethodObservers
.computeIfAbsent(k, it -> new HashSet<>())
.addAll(v));
}
if (processSyntheticObserverMethodObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessBean)
{
if (processBeanObservers == null)
{
processBeanObservers = findObservers(ProcessBean.class);
}
if (processBeanObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessBeanAttributes)
{
if (processBeanAttributesObservers == null)
{
processBeanAttributesObservers = findObservers(ProcessBeanAttributes.class);
}
if (processBeanAttributesObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessInjectionTarget)
{
if (processInjectionTargetObservers == null)
{
processInjectionTargetObservers = findObservers(ProcessInjectionTarget.class);
}
if (processInjectionTargetObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessInjectionPoint)
{
if (processInjectionPointObservers == null)
{
processInjectionPointObservers = findObservers(ProcessInjectionPoint.class);
}
if (processInjectionPointObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessObserverMethod)
{
if (processObserverMethodObservers == null)
{
processObserverMethodObservers = findObservers(ProcessObserverMethod.class);
}
if (processObserverMethodObservers.isEmpty())
{
return emptyList();
}
}
else if (event instanceof ProcessProducer)
{
if (processProducerObservers == null)
{
processProducerObservers = findObservers(ProcessProducer.class);
}
if (processProducerObservers.isEmpty())
{
return emptyList();
}
}
// note: don't forget to update filterByExtensionEventType method too
return null;
}
private Collection> filterByWithAnnotations(Collection> observersMethods, AnnotatedType annotatedType)
{
List> observerMethodsWithAnnotations = new ArrayList<>();
for (ObserverMethod super T> observerMethod : observersMethods)
{
Class[] withAnnotations = ((ContainerEventObserverMethodImpl) observerMethod).getWithAnnotations();
if (withAnnotations != null && withAnnotations.length > 0)
{
if (annotatedTypeHasAnnotations(annotatedType, withAnnotations))
{
observerMethodsWithAnnotations.add(observerMethod);
}
continue;
}
// no WithAnnotations
observerMethodsWithAnnotations.add(observerMethod);
}
return observerMethodsWithAnnotations;
}
private boolean annotatedTypeHasAnnotations(AnnotatedType annotatedType, Class extends Annotation>[] withAnnotations)
{
if (hasAnnotation(annotatedType.getAnnotations(), withAnnotations))
{
return true;
}
Set fields = annotatedType.getFields();
for (AnnotatedField annotatedField : fields)
{
if (hasAnnotation(annotatedField.getAnnotations(), withAnnotations))
{
return true;
}
}
Set annotatedMethods = annotatedType.getMethods();
for (AnnotatedMethod annotatedMethod : annotatedMethods)
{
if (hasAnnotation(annotatedMethod.getAnnotations(), withAnnotations))
{
return true;
}
for (AnnotatedParameter annotatedParameter : (List) annotatedMethod.getParameters())
{
if (hasAnnotation(annotatedParameter.getAnnotations(), withAnnotations))
{
return true;
}
}
}
Set> annotatedConstructors = annotatedType.getConstructors();
for (AnnotatedConstructor> annotatedConstructor : annotatedConstructors)
{
if (hasAnnotation(annotatedConstructor.getAnnotations(), withAnnotations))
{
return true;
}
for (AnnotatedParameter annotatedParameter : annotatedConstructor.getParameters())
{
if (hasAnnotation(annotatedParameter.getAnnotations(), withAnnotations))
{
return true;
}
}
}
return false;
}
private boolean hasAnnotation(Set annotations, Class extends Annotation>[] withAnnotations)
{
for (Class extends Annotation> withAnnotation : withAnnotations)
{
for (Annotation annotation : annotations)
{
if (withAnnotation.isAssignableFrom(annotation.annotationType()))
{
return true;
}
for (Annotation meta : annotation.annotationType().getAnnotations())
{
if (withAnnotation.isAssignableFrom(meta.annotationType()))
{
return true;
}
}
}
}
return false;
}
private Set> filterByType(T event, Type declaredEventType, boolean isLifecycleEvent)
{
if (isLifecycleEvent)
{
return filterByExtensionEventType(event, declaredEventType);
}
Class> eventClass = event.getClass();
// whether the fired event is a raw java class or a generic type
boolean isRawEvent = declaredEventType instanceof Class;
if (isRawEvent)
{
Set rawTypeObservers = observersByRawType.get(eventClass);
if (rawTypeObservers != null)
{
return rawTypeObservers;
}
}
Set> matching = new HashSet<>();
Set eventTypes = GenericsUtil.getTypeClosure(declaredEventType, eventClass);
if (GenericsUtil.containTypeVariable(eventTypes))
{
throw new IllegalArgumentException("event type may not contain unbound type variable: " + eventTypes);
}
for (Map.Entry>> observerEntry : observers.entrySet())
{
Type observedType = observerEntry.getKey();
for (Type eventType : eventTypes)
{
if ((ParameterizedType.class.isInstance(eventType) && Class.class.isInstance(observedType)
&& GenericsUtil.isAssignableFrom(true, false, observedType, ParameterizedType.class.cast(eventType).getRawType(), new HashMap<>()))
|| GenericsUtil.isAssignableFrom(true, false, observedType, eventType, new HashMap<>()))
{
Set> observerMethods = observerEntry.getValue();
for (ObserverMethod> observerMethod : observerMethods)
{
matching.add((ObserverMethod) observerMethod);
}
break;
}
}
}
if (isRawEvent)
{
// cache the result
observersByRawType.putIfAbsent(eventClass, (Set) matching);
}
return matching;
}
private Set> filterByExtensionEventType(T event, Type eventType)
{
Class> eventClass = ClassUtil.getClazz(eventType);
Set> matching = new HashSet<>();
final Map>> sourceMap;
if (event instanceof ProcessAnnotatedType) // check resolveObservers
{
sourceMap = processAnnotatedTypeObservers;
}
else if (event instanceof ProcessSyntheticObserverMethod)
{
sourceMap = processSyntheticObserverMethodObservers;
}
else if (event instanceof ProcessObserverMethod)
{
sourceMap = processObserverMethodObservers;
}
else if (event instanceof ProcessProducerField)
{
sourceMap = processProducerFieldObservers;
}
else if (event instanceof ProcessProducerMethod)
{
sourceMap = processProducerMethodObservers;
}
else if (event instanceof ProcessSyntheticBean)
{
sourceMap = processSyntheticBeanObservers;
}
else if (event instanceof ProcessProducer)
{
sourceMap = processProducerObservers;
}
else if (event instanceof ProcessManagedBean)
{
sourceMap = processManagedBeanObservers;
}
else if (event instanceof ProcessBean)
{
sourceMap = processBeanObservers;
}
else if (event instanceof ProcessBeanAttributes)
{
sourceMap = processBeanAttributesObservers;
}
else if (event instanceof ProcessInjectionTarget)
{
sourceMap = processInjectionTargetObservers;
}
else if (event instanceof ProcessInjectionPoint)
{
sourceMap = processInjectionPointObservers;
}
else
{
sourceMap = observers;
}
Set keySet = sourceMap.keySet();
for (Type type : keySet)
{
Class> beanClass;
Class> observerClass = ClassUtil.getClazz(type);
if(observerClass != null)
{
if(observerClass.isAssignableFrom(eventClass))
{
//ProcessBean,ProcessAnnotateType, ProcessInjectionTarget
if(WebBeansUtil.isExtensionBeanEventType(eventType))
{
if(WebBeansUtil.isDefaultExtensionBeanEventType(observerClass))
{
GenericBeanEvent genericBeanEvent = (GenericBeanEvent)event;
beanClass = genericBeanEvent.getBeanClassFor(observerClass);
if(ClassUtil.isParametrizedType(type))
{
Type secondParam = null;
if (TwoParametersGenericBeanEvent.class.isInstance(event))
{
secondParam = TwoParametersGenericBeanEvent.class.cast(event).getInjectionType();
}
addToMatchingWithParametrizedForBeans(type, matching, beanClass, secondParam);
}
else
{
addToMatching(type, matching);
}
}
}
//ProcessProducer, ProcessProducerMethod, ProcessProducerField,ProcessObserverMEthod
else if(WebBeansUtil.isExtensionProducerOrObserverEventType(eventType))
{
GenericProducerObserverEvent genericBeanEvent = (GenericProducerObserverEvent)event;
beanClass = genericBeanEvent.getBeanClass();
Class> producerOrObserverReturnClass = genericBeanEvent.getProducerOrObserverType();
if(WebBeansUtil.isDefaultExtensionProducerOrObserverEventType(observerClass))
{
boolean processProducerEvent = false;
if(observerClass.equals(ProcessProducer.class))
{
processProducerEvent = true;
}
if(ClassUtil.isParametrizedType(type))
{
addToMatchingWithParametrizedForProducers(processProducerEvent,type, beanClass, producerOrObserverReturnClass, matching);
}
else
{
addToMatching(type, matching);
}
}
else if(observerClass.isAssignableFrom(eventClass))
{
if(ClassUtil.isParametrizedType(type))
{
addToMatchingWithParametrizedForBeans(type, matching, beanClass, null);
}
else
{
addToMatching(type, matching);
}
}
}
//BeforeBeanDiscovery,AfterBeanDiscovery,AfterDeploymentValidation
//BeforeShutDown Events
else
{
if(observerClass.isAssignableFrom(eventClass))
{
addToMatching(type, matching);
}
}
}
}
}
return matching;
}
/**
* Returns true if fired event class is assignable with
* given observer type argument.
* @param beanClass fired event class.
* @param observerTypeActualArg actual type argument,
* such as in case ProcessProducerField<Book> is Book.class
* @return true if fired event class is assignable with
* given observer type argument.
*/
private boolean checkEventTypeParameterForExtensions(Type beanClass, Type observerTypeActualArg)
{
if(ClassUtil.isTypeVariable(observerTypeActualArg))
{
TypeVariable> tv = (TypeVariable>)observerTypeActualArg;
Type tvBound = tv.getBounds()[0];
if(tvBound instanceof Class)
{
Class> clazzTvBound = (Class>)tvBound;
if(Class.class.isInstance(beanClass) && clazzTvBound.isAssignableFrom(Class.class.cast(beanClass)))
{
return true;
}
}
}
else if(ClassUtil.isWildCardType(observerTypeActualArg))
{
return ClassUtil.checkRequiredTypeIsWildCard(beanClass, observerTypeActualArg);
}
else if(observerTypeActualArg instanceof Class)
{
Class> observerClass = (Class>)observerTypeActualArg;
if(Class.class.isInstance(beanClass) && observerClass.isAssignableFrom(Class.class.cast(beanClass)))
{
return true;
}
}
else if (observerTypeActualArg instanceof ParameterizedType)
{
return GenericsUtil.isAssignableFrom(false, true, observerTypeActualArg, beanClass, new HashMap<>());
}
return false;
}
private void addToMatching(Type type, Set> matching)
{
Set> wrappers = observers.get(type);
for (ObserverMethod> wrapper : wrappers)
{
matching.add((ObserverMethod) wrapper);
}
}
private void addToMatchingWithParametrizedForBeans(Type type, Set> matching,
Class> beanClass, Type secondParam)
{
ParameterizedType pt = (ParameterizedType)type;
Type[] actualArgs = pt.getActualTypeArguments();
if(actualArgs.length == 0)
{
Class> rawType = (Class>)pt.getRawType();
if(rawType.isAssignableFrom(beanClass))
{
addToMatching(type, matching);
}
}
else
{
if(checkEventTypeParameterForExtensions(beanClass, actualArgs[0])
&& (secondParam == null || actualArgs.length == 1
|| checkEventTypeParameterForExtensions(secondParam, actualArgs[1])
|| GenericsUtil.isAssignableFrom(true, false, actualArgs[1], secondParam, new HashMap<>())))
{
addToMatching(type, matching);
}
}
}
/**
* Add to matching.
* @param generic observer method parameter type
* fired event because of observer method or not
* @param type one of observer method parameter base type
* @param beanClass observer method owner bean class
* @param producerOrObserverReturnClass observer even normal class
* @param matching set of observer method that match the given type
*/
private void addToMatchingWithParametrizedForProducers(boolean processProducer, Type type, Class> beanClass,
Class> producerOrObserverReturnClass, Set> matching )
{
ParameterizedType pt = (ParameterizedType)type;
Type[] actualArgs = pt.getActualTypeArguments();
if(actualArgs.length == 0)
{
Class> rawType = (Class>)pt.getRawType();
if(rawType.isAssignableFrom(beanClass))
{
addToMatching(type, matching);
}
}
else
{
//Bean class argument
//For observer related event, observer owner bean class.
Type beanClassArg = actualArgs[1];
//Event payload
Type returnClassArg = actualArgs[0];
//For ProcessProducer
if(processProducer)
{
beanClassArg = actualArgs[0];
returnClassArg = actualArgs[1];
}
if(checkEventTypeParameterForExtensions(beanClass, beanClassArg) &&
checkEventTypeParameterForExtensions(producerOrObserverReturnClass, returnClassArg))
{
addToMatching(type, matching);
}
}
}
/**
* filter out all {@code ObserverMethod}s which do not fit the given
* qualifiers.
*/
private Collection> filterByQualifiers(Collection> observers, Set eventQualifiers)
{
List> matching = new ArrayList<>(observers.size());
search: for (ObserverMethod super T> ob : observers)
{
Set qualifiers = ob.getObservedQualifiers();
if (qualifiers.size() > eventQualifiers.size())
{
continue;
}
for (Annotation qualifier : qualifiers)
{
boolean found = false;
for(Annotation inList : eventQualifiers)
{
if(AnnotationUtil.isCdiAnnotationEqual(inList, qualifier))
{
found = true;
break;
}
}
if(!found)
{
continue search;
}
}
matching.add(ob);
}
return matching;
}
public NotificationOptions getDefaultNotificationOptions()
{
return defaultNotificationOptions;
}
/**
* Fire the given event
* @param notificationOptions if {@code null} then this is a synchronous event. Otherwise fireAsync
*/
public CompletionStage 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)));
}
public CompletionStage doFireEvent(Object event, EventMetadataImpl metadata, boolean isLifecycleEvent,
NotificationOptions notificationOptions, boolean async,
List> observerMethods)
{
prepareObserverListForFire(isLifecycleEvent, async, observerMethods);
if (observerMethods.isEmpty())
{
if (async)
{
return completedFuture((T) event);
}
return null;
}
EventContextImpl
© 2015 - 2025 Weber Informatics LLC | Privacy Policy