/* * JBoss, Home of Professional Open Source * Copyright 2011, 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.solder.exception.control; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.text.MessageFormat; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedParameter; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.InjectionPoint; import org.jboss.solder.bean.Beans; import org.jboss.solder.bean.ImmutableInjectionPoint; import org.jboss.solder.literal.AnyLiteral; import org.jboss.solder.reflection.annotated.InjectableMethod; import org.jboss.solder.exception.control.CaughtException; import org.jboss.solder.exception.control.HandlerMethod; import org.jboss.solder.exception.control.Handles; import org.jboss.solder.exception.control.TraversalMode; /** * Implementation of {@link org.jboss.solder.exception.control.HandlerMethod}. * * @param <T> Type of the exception this handler handles. */ public class HandlerMethodImpl<T extends Throwable> implements HandlerMethod<T> { private final Class<?> beanClass; private Bean<?> bean; private final Set<Annotation> qualifiers; private final Type exceptionType; private final AnnotatedMethod<?> handler; private final TraversalMode traversalMode; private final int precedence; private final Method javaMethod; private final AnnotatedParameter<?> handlerParameter; private final Set<InjectionPoint> injectionPoints; /** * Determines if the given method is a handler by looking for the {@link Handles} annotation on a parameter. * * @param method method to search * @return true if {@link Handles} is found, false otherwise */ public static boolean isHandler(final AnnotatedMethod<?> method) { if (method == null) { throw new IllegalArgumentException("Method must not be null"); } for (AnnotatedParameter<?> param : method.getParameters()) { if (param.isAnnotationPresent(Handles.class)) { return true; } } return false; } public static AnnotatedParameter<?> findHandlerParameter(final AnnotatedMethod<?> method) { if (!isHandler(method)) { throw new IllegalArgumentException("Method is not a valid handler"); } AnnotatedParameter<?> returnParam = null; for (AnnotatedParameter<?> param : method.getParameters()) { if (param.isAnnotationPresent(Handles.class)) { returnParam = param; break; } } return returnParam; } /** * Sole Constructor. * * @param method found handler * @param bm active BeanManager * @throws IllegalArgumentException if method is null, has no params or first param is not annotated with * {@link Handles} */ public HandlerMethodImpl(final AnnotatedMethod<?> method, final BeanManager bm) { if (!HandlerMethodImpl.isHandler(method)) { throw new IllegalArgumentException(MessageFormat.format("{0} is not a valid handler", method)); } final Set<Annotation> tmpQualifiers = new HashSet<Annotation>(); this.handler = method; this.javaMethod = method.getJavaMember(); this.handlerParameter = findHandlerParameter(method); if (!this.handlerParameter.isAnnotationPresent(Handles.class)) { throw new IllegalArgumentException("Method is not annotated with @Handles"); } this.traversalMode = this.handlerParameter.getAnnotation(Handles.class).during(); this.precedence = this.handlerParameter.getAnnotation(Handles.class).precedence(); tmpQualifiers.addAll(Beans.getQualifiers(bm, this.handlerParameter.getAnnotations())); if (tmpQualifiers.isEmpty()) { tmpQualifiers.add(AnyLiteral.INSTANCE); } this.qualifiers = tmpQualifiers; this.beanClass = method.getJavaMember().getDeclaringClass(); this.exceptionType = ((ParameterizedType) this.handlerParameter.getBaseType()).getActualTypeArguments()[0]; this.injectionPoints = new HashSet<InjectionPoint>(method.getParameters().size() - 1); for (AnnotatedParameter<?> param : method.getParameters()) { if (!param.equals(this.handlerParameter)) this.injectionPoints.add(new ImmutableInjectionPoint(param, bm, this.getBean(bm), false, false)); } } /** * {@inheritDoc} */ public Class<?> getBeanClass() { return this.beanClass; } /** * {@inheritDoc} */ public synchronized Bean<?> getBean(BeanManager bm) { if (this.bean == null) { this.bean = bm.resolve(bm.getBeans(this.beanClass)); } return this.bean; } /** * {@inheritDoc} */ public Set<Annotation> getQualifiers() { return Collections.unmodifiableSet(this.qualifiers); } /** * {@inheritDoc} */ public Type getExceptionType() { return this.exceptionType; } /** * {@inheritDoc} */ public void notify(final CaughtException<T> event, final BeanManager bm) { CreationalContext<?> ctx = null; try { ctx = bm.createCreationalContext(null); Object handlerInstance = bm.getReference(this.getBean(bm), this.beanClass, ctx); InjectableMethod<?> im = createInjectableMethod(this.handler, this.getBean(bm), bm); im.invoke(handlerInstance, ctx, new OutboundParameterValueRedefiner(event, bm, this)); } finally { if (ctx != null) { ctx.release(); } } } private <X> InjectableMethod<X> createInjectableMethod(AnnotatedMethod<X> handlerMethod, Bean<?> bean, BeanManager manager) { return new InjectableMethod<X>(handlerMethod, bean, manager); } /** * {@inheritDoc} */ public TraversalMode getTraversalMode() { return this.traversalMode; } /** * {@inheritDoc} */ public int getPrecedence() { return this.precedence; } /** * {@inheritDoc} */ public Method getJavaMethod() { return this.javaMethod; } public AnnotatedParameter<?> getHandlerParameter() { return this.handlerParameter; } public Set<InjectionPoint> getInjectionPoints() { return new HashSet<InjectionPoint>(this.injectionPoints); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } HandlerMethod<?> that = (HandlerMethod<?>) o; if (!qualifiers.equals(that.getQualifiers())) { return false; } if (!exceptionType.equals(that.getExceptionType())) { return false; } if (precedence != that.getPrecedence()) { return false; } return traversalMode == that.getTraversalMode(); } @Override public int hashCode() { int result = beanClass.hashCode(); result = 5 * result + qualifiers.hashCode(); result = 5 * result + exceptionType.hashCode(); result = 5 * result + traversalMode.hashCode(); result = 5 * result + precedence; result = 5 * result + javaMethod.hashCode(); result = 5 * result + handlerParameter.hashCode(); return result; } @Override public String toString() { return new StringBuilder("Qualifiers: ").append(this.qualifiers).append(" ") .append("TraversalMode: ").append(this.traversalMode).append(" ") .append("Handles Type: ").append(this.exceptionType).append(" ") .append("Precedence: ").append(this.precedence).append(" ") .append(this.handler.toString()).toString(); } }