All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.webbeans.event.NotificationManager Maven / Gradle / Ivy

The newest version!
/*
 * 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.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.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.enterprise.event.ObserverException;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.enterprise.event.TransactionPhase;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ObserverMethod;
import javax.enterprise.inject.spi.ProcessProducer;
import javax.enterprise.util.TypeLiteral;

import org.apache.webbeans.component.AbstractOwbBean;
import org.apache.webbeans.config.OWBLogConst;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.exception.WebBeansException;
import org.apache.webbeans.logger.WebBeansLoggerFacade;
import org.apache.webbeans.portable.events.generics.GenericBeanEvent;
import org.apache.webbeans.portable.events.generics.GenericProducerObserverEvent;
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.WebBeansUtil;

@SuppressWarnings("unchecked")
public final class NotificationManager
{
    private final Map>> observers = new ConcurrentHashMap>>();
    private final WebBeansContext webBeansContext;

    public NotificationManager(WebBeansContext webBeansContext)
    {
        this.webBeansContext = webBeansContext;
    }

    public  void addObserver(ObserverMethod observer, Type eventType)
    {
        webBeansContext.getAnnotationManager().checkQualifierConditions(observer.getObservedQualifiers());

        Set> set = observers.get(eventType);
        if (set == null)
        {
            set = new HashSet>();
            observers.put(eventType, set);
        }

        set.add(observer);
    }

    public  void addObserver(ObserverMethod observer, TypeLiteral typeLiteral)
    {
        EventUtil.checkEventType(typeLiteral.getRawType());

        addObserver(observer, typeLiteral.getType());
    }

    /**
     * 

This method shall only be called for subclasses. * It will disable all observer methods which are overridden * in the given subclass.

*/ public void disableOverriddenObservers(Class subClass) { for (Set> observerMethods: observers.values()) { for (Iterator> i = observerMethods.iterator(); i.hasNext();) { ObserverMethod observer = i.next(); if (observer instanceof ObserverMethodImpl) { AnnotatedMethod observerMethod = ((ObserverMethodImpl)observer).getObserverMethod(); //needs to be a subtype and not the class itself (otherwise all observer-methods get removed) if (subClass.isAssignableFrom(observerMethod.getJavaMember().getDeclaringClass()) && !subClass.equals(observerMethod.getJavaMember().getDeclaringClass())) { try { subClass.getMethod(observerMethod.getJavaMember().getName(), observerMethod.getJavaMember().getParameterTypes()); i.remove(); } catch(NoSuchMethodException nsme) { // that's perfectly fine. // it means that we don't need to remove anything because the // observer method didn't get overridden. } } } } } } public Set> resolveObservers(T event, EventMetadata metadata) { EventUtil.checkEventBindings(webBeansContext, metadata.getQualifiers()); Type eventType = metadata.getType(); Set> observersMethods = filterByType(event, eventType); observersMethods = filterByQualifiers(observersMethods, metadata.getQualifiers()); //this check for the TCK is only needed if no observer was found if (observersMethods.isEmpty()) { EventUtil.checkQualifierImplementations(metadata.getQualifiers()); } return observersMethods; } private Set> filterByType(T event, Type eventType) { if(WebBeansUtil.isExtensionEventType(eventType)) { return filterByExtensionEventType(event, eventType); } Class eventClass = ClassUtil.getClass(eventType); Set> matching = new HashSet>(); Set types = new HashSet(); types.add(eventType); Type superClazz = eventClass.getGenericSuperclass(); if(superClazz != null) { types.add(superClazz); } Type[] genericInts = eventClass.getGenericInterfaces(); if(genericInts != null && genericInts.length > 0) { for(Type genericInt : genericInts) { types.add(genericInt); } } Set keySet = observers.keySet(); for (Type type : keySet) { for (Type check : types) { if (ClassUtil.checkEventTypeAssignability(check, type)) { Set> wrappers = observers.get(type); for (ObserverMethod wrapper : wrappers) { matching.add((ObserverMethod) wrapper); } break; } } } return matching; } private Set> filterByExtensionEventType(T event, Type eventType) { Class eventClass = ClassUtil.getClazz(eventType); Set> matching = new HashSet>(); Set keySet = observers.keySet(); for (Type type : keySet) { Class beanClass = null; 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)) { addToMathingWithParametrizedForBeans(type,beanClass,matching); } 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)) { addToMathingWithParametrizedForBeans(type,beanClass,matching); } 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(Class 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(clazzTvBound.isAssignableFrom(beanClass)) { return true; } } } else if(ClassUtil.isWildCardType(observerTypeActualArg)) { return ClassUtil.checkRequiredTypeIsWildCard(beanClass, observerTypeActualArg); } else if(observerTypeActualArg instanceof Class) { Class observerClass = (Class)observerTypeActualArg; if(observerClass.isAssignableFrom(beanClass)) { return true; } } return false; } private void addToMatching(Type type, Set> matching) { Set> wrappers = observers.get(type); for (ObserverMethod wrapper : wrappers) { matching.add((ObserverMethod) wrapper); } } private void addToMathingWithParametrizedForBeans(Type type, Class beanClass, 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 { if(checkEventTypeParameterForExtensions(beanClass, actualArgs[0])) { 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 Set> filterByQualifiers(Set> observers, Set eventQualifiers) { Set> matching = new HashSet>(); search: for (ObserverMethod 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 void fireEvent(Object event, EventMetadata metadata, boolean isLifecycleEvent) { Set> observerMethods = resolveObservers(event, metadata); for (ObserverMethod 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.equals(TransactionPhase.IN_PROGRESS)) { TransactionService transactionService = webBeansContext.getService(TransactionService.class); if(transactionService != null) { transactionService.registerTransactionSynchronization(phase, observer, event); } else { if (observer instanceof OwbObserverMethod) { ((OwbObserverMethod)observer).notify(event, metadata); } else { observer.notify(event); } } } else { if (observer instanceof OwbObserverMethod) { ((OwbObserverMethod)observer).notify(event, metadata); } else { observer.notify(event); } } } catch (WebBeansException e) { Throwable exc = e.getCause(); if(exc instanceof InvocationTargetException) { InvocationTargetException invt = (InvocationTargetException)exc; exc = invt.getCause(); } 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; } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new WebBeansException(e); } } } /** * Gets observer method from given annotated method. * @param bean type info * @param annotatedMethod annotated method for observer * @param bean bean instance * @return ObserverMethod */ public ObserverMethod getObservableMethodForAnnotatedMethod(AnnotatedMethod annotatedMethod, AbstractOwbBean bean) { Asserts.assertNotNull(annotatedMethod, "annotatedMethod parameter can not be null"); Observes observes = AnnotationUtil.getAnnotatedMethodFirstParameterAnnotation(annotatedMethod, Observes.class); boolean ifExist = false; if(observes != null) { if (observes.notifyObserver().equals(Reception.IF_EXISTS)) { ifExist = true; } } //Looking for qualifiers Annotation[] observerQualifiers = bean.getWebBeansContext().getAnnotationManager().getAnnotatedMethodFirstParameterQualifierWithGivenAnnotation( annotatedMethod, Observes.class); //Getting observer event type Type type = AnnotationUtil.getAnnotatedMethodFirstParameterWithAnnotation(annotatedMethod, Observes.class); //Observer creation from annotated method ObserverMethodImpl observer = new ObserverMethodImpl(bean, annotatedMethod, ifExist, observerQualifiers, type); //Adds this observer addObserver(observer, type); return observer; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy