001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.shiro.event.support;
020
021import org.apache.shiro.event.Subscribe;
022import org.apache.shiro.util.ClassUtils;
023
024import java.lang.annotation.Annotation;
025import java.lang.reflect.Method;
026import java.util.ArrayList;
027import java.util.Collections;
028import java.util.List;
029
030/**
031 * Inspects an object for annotated methods of interest and creates an {@link EventListener} instance for each method
032 * discovered.  An event bus will call the resulting listeners as relevant events arrive.
033 * <p/>
034 * The default {@link #setAnnotationClass(Class) annotationClass} is {@link Subscribe}, indicating each
035 * {@link Subscribe}-annotated method will be represented as an EventListener.
036 *
037 * @see SingleArgumentMethodEventListener
038 * @since 1.3
039 */
040public class AnnotationEventListenerResolver implements EventListenerResolver {
041
042    private Class<? extends Annotation> annotationClass;
043
044    public AnnotationEventListenerResolver() {
045        this.annotationClass = Subscribe.class;
046    }
047
048    /**
049     * Returns a new collection of {@link EventListener} instances, each instance corresponding to an annotated
050     * method discovered on the specified {@code instance} argument.
051     *
052     * @param instance the instance to inspect for annotated event handler methods.
053     * @return a new collection of {@link EventListener} instances, each instance corresponding to an annotated
054     *         method discovered on the specified {@code instance} argument.
055     */
056    public List<EventListener> getEventListeners(Object instance) {
057        if (instance == null) {
058            return Collections.emptyList();
059        }
060
061        List<Method> methods = ClassUtils.getAnnotatedMethods(instance.getClass(), getAnnotationClass());
062        if (methods == null || methods.isEmpty()) {
063            return Collections.emptyList();
064        }
065
066        List<EventListener> listeners = new ArrayList<EventListener>(methods.size());
067
068        for (Method m : methods) {
069            listeners.add(new SingleArgumentMethodEventListener(instance, m));
070        }
071
072        return listeners;
073    }
074
075    /**
076     * Returns the type of annotation that indicates a method that should be represented as an {@link EventListener},
077     * defaults to {@link Subscribe}.
078     *
079     * @return the type of annotation that indicates a method that should be represented as an {@link EventListener},
080     *         defaults to {@link Subscribe}.
081     */
082    public Class<? extends Annotation> getAnnotationClass() {
083        return annotationClass;
084    }
085
086    /**
087     * Sets the type of annotation that indicates a method that should be represented as an {@link EventListener}.
088     * The default value is {@link Subscribe}.
089     *
090     * @param annotationClass the type of annotation that indicates a method that should be represented as an
091     *                        {@link EventListener}.  The default value is {@link Subscribe}.
092     */
093    public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
094        this.annotationClass = annotationClass;
095    }
096}