/* * JBoss, Home of Professional Open Source * Copyright 2016, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed 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.jboss.weld.bootstrap.events.configurator; import static org.jboss.weld.util.Preconditions.checkArgumentNotNull; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Priority; import javax.enterprise.event.ObserverException; import javax.enterprise.event.Observes; import javax.enterprise.event.ObservesAsync; import javax.enterprise.event.Reception; import javax.enterprise.event.TransactionPhase; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedParameter; import javax.enterprise.inject.spi.EventContext; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ObserverMethod; import javax.enterprise.inject.spi.configurator.ObserverMethodConfigurator; import org.jboss.weld.event.SyntheticObserverMethod; import org.jboss.weld.logging.EventLogger; import org.jboss.weld.resolution.CovariantTypes; import org.jboss.weld.util.collections.ImmutableSet; import org.jboss.weld.util.reflection.Formats; /** * * @author Martin Kouba */ public class ObserverMethodConfiguratorImpl<T> implements ObserverMethodConfigurator<T>, Configurator<ObserverMethod<T>> { private Class<?> beanClass; private Type observedType; private final Set<Annotation> observedQualifiers; private Reception reception; private TransactionPhase txPhase; private int priority; private boolean isAsync; private EventConsumer<T> notifyCallback; private final Extension extension; public ObserverMethodConfiguratorImpl(Extension extension) { this.reception = Reception.ALWAYS; this.txPhase = TransactionPhase.IN_PROGRESS; this.observedQualifiers = new HashSet<>(); this.priority = ObserverMethod.DEFAULT_PRIORITY; this.extension = extension; this.beanClass = extension.getClass(); } public ObserverMethodConfiguratorImpl(ObserverMethod<T> observerMethod, Extension extension) { this(extension); read(observerMethod); notifyWith(e -> observerMethod.notify(e)); } @Override public ObserverMethodConfigurator<T> read(Method method) { checkArgumentNotNull(method); Set<Parameter> eventParameters = Configurators.getAnnotatedParameters(method, Observes.class, ObservesAsync.class); checkEventParams(eventParameters, method); Parameter eventParameter = eventParameters.iterator().next(); Observes observesAnnotation = eventParameter.getAnnotation(Observes.class); if (observesAnnotation != null) { reception(observesAnnotation.notifyObserver()); transactionPhase(observesAnnotation.during()); } else { reception(eventParameter.getAnnotation(ObservesAsync.class).notifyObserver()); } Priority priority = method.getAnnotation(Priority.class); if (priority != null) { priority(priority.value()); } beanClass(eventParameter.getDeclaringExecutable().getDeclaringClass()); observedType(eventParameter.getType()); qualifiers(Configurators.getQualifiers(eventParameter)); return this; } @Override public ObserverMethodConfigurator<T> read(AnnotatedMethod<?> method) { checkArgumentNotNull(method); Set<AnnotatedParameter<?>> eventParameters = method.getParameters().stream() .filter((p) -> p.isAnnotationPresent(Observes.class) || p.isAnnotationPresent(ObservesAsync.class)).collect(Collectors.toSet()); checkEventParams(eventParameters, method.getJavaMember()); AnnotatedParameter<?> eventParameter = eventParameters.iterator().next(); Observes observesAnnotation = eventParameter.getAnnotation(Observes.class); if (observesAnnotation != null) { reception(observesAnnotation.notifyObserver()); transactionPhase(observesAnnotation.during()); } else { reception(eventParameter.getAnnotation(ObservesAsync.class).notifyObserver()); } Priority priority = method.getAnnotation(Priority.class); if (priority != null) { priority(priority.value()); } beanClass(eventParameter.getDeclaringCallable().getDeclaringType().getJavaClass()); observedType(eventParameter.getBaseType()); qualifiers(Configurators.getQualifiers(eventParameter)); return this; } @Override public ObserverMethodConfigurator<T> read(final ObserverMethod<T> observerMethod) { checkArgumentNotNull(observerMethod); beanClass(observerMethod.getBeanClass()); observedType(observerMethod.getObservedType()); qualifiers(observerMethod.getObservedQualifiers()); reception(observerMethod.getReception()); transactionPhase(observerMethod.getTransactionPhase()); priority(observerMethod.getPriority()); async(observerMethod.isAsync()); return this; } @Override public ObserverMethodConfigurator<T> beanClass(Class<?> beanClass) { this.beanClass = beanClass; return this; } @Override public ObserverMethodConfigurator<T> observedType(Type type) { checkArgumentNotNull(type); if (observedType != null && !CovariantTypes.isAssignableFrom(observedType, type)) { EventLogger.LOG.originalObservedTypeIsNotAssignableFrom(observedType, type, extension); } observedType = type; return this; } @Override public ObserverMethodConfigurator<T> addQualifier(Annotation qualifier) { checkArgumentNotNull(qualifier); this.observedQualifiers.add(qualifier); return this; } @Override public ObserverMethodConfigurator<T> addQualifiers(Annotation... qualifiers) { checkArgumentNotNull(qualifiers); Collections.addAll(this.observedQualifiers, qualifiers); return this; } @Override public ObserverMethodConfigurator<T> addQualifiers(Set<Annotation> qualifiers) { checkArgumentNotNull(qualifiers); this.observedQualifiers.addAll(qualifiers); return this; } @Override public ObserverMethodConfigurator<T> qualifiers(Annotation... qualifiers) { this.observedQualifiers.clear(); addQualifiers(qualifiers); return this; } @Override public ObserverMethodConfigurator<T> qualifiers(Set<Annotation> qualifiers) { this.observedQualifiers.clear(); addQualifiers(qualifiers); return this; } @Override public ObserverMethodConfigurator<T> reception(Reception reception) { checkArgumentNotNull(reception); this.reception = reception; return this; } @Override public ObserverMethodConfigurator<T> transactionPhase(TransactionPhase transactionPhase) { checkArgumentNotNull(transactionPhase); this.txPhase = transactionPhase; return this; } @Override public ObserverMethodConfigurator<T> priority(int priority) { this.priority = priority; return this; } @Override public ObserverMethodConfigurator<T> notifyWith(EventConsumer<T> callback) { checkArgumentNotNull(callback); this.notifyCallback = callback; return this; } @Override public ObserverMethodConfigurator<T> async(boolean async) { this.isAsync = async; return this; } @Override public ObserverMethod<T> complete() { return new ImmutableObserverMethod<>(this); } private <P> void checkEventParams(Set<P> eventParams, Method method) { if (eventParams.size() != 1) { EventLogger.LOG.noneOrMultipleEventParametersDeclared(method, Formats.formatAsStackTraceElement(method)); } } /** * * * @param <T> */ static class ImmutableObserverMethod<T> implements SyntheticObserverMethod<T> { private final Class<?> beanClass; private final Type observedType; private final Set<Annotation> observedQualifiers; private final Reception reception; private final TransactionPhase txPhase; private final int priority; private final boolean isAsync; private final EventConsumer<T> notifyCallback; /** * * @param configurator */ ImmutableObserverMethod(ObserverMethodConfiguratorImpl<T> configurator) { if (configurator.notifyCallback == null) { throw EventLogger.LOG.notifyMethodNotImplemented(configurator); } this.beanClass = configurator.beanClass; this.observedType = configurator.observedType; this.observedQualifiers = ImmutableSet.copyOf(configurator.observedQualifiers); this.reception = configurator.reception; this.txPhase = configurator.txPhase; this.priority = configurator.priority; this.isAsync = configurator.isAsync; this.notifyCallback = configurator.notifyCallback; } @Override public int getPriority() { return priority; } @Override public Class<?> getBeanClass() { return beanClass; } @Override public Type getObservedType() { return observedType; } @Override public Set<Annotation> getObservedQualifiers() { return observedQualifiers; } @Override public Reception getReception() { return reception; } @Override public TransactionPhase getTransactionPhase() { return txPhase; } @Override public void notify(EventContext<T> eventContext) { try { notifyCallback.accept(eventContext); } catch (Exception e) { throw new ObserverException(e); } } @Override public boolean isAsync() { return isAsync; } @Override public boolean isEventMetadataRequired() { return true; } } }