001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2016-2018 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Affero General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 013 * for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jgrapes.core.annotation; 020 021import java.lang.annotation.Annotation; 022import java.lang.annotation.Documented; 023import java.lang.annotation.ElementType; 024import java.lang.annotation.Retention; 025import java.lang.annotation.RetentionPolicy; 026import java.lang.annotation.Target; 027import java.lang.reflect.Method; 028import java.util.HashMap; 029import org.jgrapes.core.Channel; 030import org.jgrapes.core.ComponentType; 031import org.jgrapes.core.Event; 032import org.jgrapes.core.HandlerScope; 033 034/** 035 * This annotation tags some other annotation as a handler annotation. 036 * The tagged annotation can then be used to mark a method as a handler. 037 * 038 * Every handler definition annotation must provide an {@link Evaluator} 039 * to allow access to the properties of the handler annotation in a 040 * uniform way. 041 */ 042@Documented 043@Retention(RetentionPolicy.RUNTIME) 044@Target(ElementType.ANNOTATION_TYPE) 045public @interface HandlerDefinition { 046 047 /** 048 * Returns the evaluator for the annotated handler annotation. 049 * 050 * @return the evaluator 051 */ 052 Class<? extends Evaluator> evaluator(); 053 054 /** 055 * This interface allows access to the properties defined by arbitrary 056 * handler annotations in a uniform way. Handler annotations 057 * must specify the scope of a handler, i.e. for which events and 058 * channels the handler should be invoked, and the priority of 059 * the handler. 060 */ 061 interface Evaluator { 062 063 /** 064 * Returns the information about the events and channels handled 065 * by the handler that annotates the given method of the given 066 * comonent as a {@link HandlerScope} object. This method 067 * is invoked during object initialization. It may return 068 * {@code null} if a handler is not supposed to be added for 069 * this method during initialization (dynamic handler, 070 * see {@link Handler#dynamic()}). 071 * 072 * @param component the component 073 * @param method the annotated method 074 * @param channelReplacements replacements for channel classes in 075 * the annotation's `channels` element 076 * @return the scope or {@code null} if a handler for the method 077 * should not be created 078 */ 079 HandlerScope scope(ComponentType component, Method method, 080 ChannelReplacements channelReplacements); 081 082 /** 083 * Returns the priority defined by the annotation 084 * 085 * @param annotation the annotation 086 * @return the priority 087 */ 088 int priority(Annotation annotation); 089 090 /** 091 * Utility method for checking if the method can be used as handler. 092 * 093 * @param method the method 094 * @return the result 095 */ 096 static boolean checkMethodSignature(Method method) { 097 return method.getParameterTypes().length == 0 098 || method.getParameterTypes().length == 1 099 && Event.class.isAssignableFrom( 100 method.getParameterTypes()[0]) 101 || (method.getParameterTypes().length == 2 102 && Event.class.isAssignableFrom( 103 method.getParameterTypes()[0])) 104 && Channel.class.isAssignableFrom( 105 method.getParameterTypes()[1]); 106 } 107 } 108 109 /** 110 * Represents channel (criteria) replacements that are to 111 * be applied to `channels` elements of {@link Handler} 112 * annotations. 113 */ 114 @SuppressWarnings("serial") 115 class ChannelReplacements // NOPMD (for missing serialVersionUID) 116 extends HashMap<Class<? extends Channel>, Object> { 117 118 /** 119 * Create a new replacements specification object. 120 * 121 * @return the channel replacements 122 */ 123 public static ChannelReplacements create() { 124 return new ChannelReplacements(); 125 } 126 127 /** 128 * Adds a replacements to the replacements. 129 * 130 * @param annotationCriterion the criterion used in the annotation 131 * @param replacement the replacement 132 * @return the channel replacements for easy chaining 133 */ 134 public ChannelReplacements add( 135 Class<? extends Channel> annotationCriterion, 136 Channel replacement) { 137 put(annotationCriterion, replacement.defaultCriterion()); 138 return this; 139 } 140 } 141}