1 package cz.cuni.amis.pogamut.sposh.executor; 2 3 import cz.cuni.amis.pogamut.sposh.context.Context; 4 import cz.cuni.amis.pogamut.sposh.engine.VariableContext; 5 import cz.cuni.amis.pogamut.sposh.exceptions.MethodException; 6 import java.lang.reflect.InvocationTargetException; 7 import java.text.MessageFormat; 8 9 /** 10 * Create new parametrized {@link ISense sense} using reflection. The senses 11 * created by subclassing this class will have access to the desired parameters 12 * directly from method parameters. 13 * 14 * In order to create new parametrized sense, subclass this class and create 15 * method <tt>public RETURN query</tt>. RETURN is same type as passed to the 16 * generics. All parameters of the <tt>query</tt> method must be annotated by 17 * the {@link Param} and must be one types supported by POSH (currently {@link String}, {@link Double}, {@link Boolean} 18 * and {@link Integer}). 19 * 20 * If you so desire, no parameters are necessary, thus to create parameterless 21 * sense simply use <tt>public RETURN query() {...}</tt> method, but it is not 22 * very useful, it is better to directly subclass {@link StateSense} that forces 23 * you to implement {@link ISense#query(cz.cuni.amis.pogamut.sposh.engine.VariableContext) 24 * } method. 25 * 26 * <b>NOTE:</b> interfaces and other mechanisms of Java are not capable to 27 * ensure the presence of parametrized <tt>query</tt> method at compile time. 28 * The presence of method will be checked at the moment of instantiation. 29 * 30 * Example: 31 * <pre> 32 * public class FlagIsOnGround extends FlagSense<AttackbotContext, Boolean> { 33 34 public FlagIsOnGround(AttackbotContext ctx) { 35 super(ctx, Boolean.class); 36 } 37 38 public Boolean query(&064;Param("$teamname") String teamName) { 39 40 * </pre> 41 * 42 * @see ParamsAction 43 * 44 * @param <RETURN> Return type of query. 45 * @author Honza Havlicek 46 */ 47 public abstract class ParamsSense<CONTEXT extends Context, RETURN> extends StateSense<CONTEXT, RETURN> { 48 49 private static final String QUERY_METHOD_NAME = "query"; 50 private final ParamsMethod<RETURN> queryMethod; 51 52 /** 53 * Create new parametrized sense. 54 * 55 * @param ctx Shared info of bot + tools for manipulating the world. 56 * @param returnCls Class of RETURN type. Required by reflection for finding 57 * the correct query method (generic types are erased during compile time). 58 * Currently only <tt>String.class</tt>, <tt>Double.TYPE</tt> and 59 * <tt>Integer.TYPE</tt> return values are supported. 60 */ 61 protected ParamsSense(CONTEXT ctx, Class<RETURN> returnCls) { 62 super(ctx); 63 64 queryMethod = new ParamsMethod<RETURN>(getClass(), QUERY_METHOD_NAME, returnCls); 65 } 66 67 @SuppressWarnings({ "unchecked", "rawtypes" }) 68 protected ParamsSense(CONTEXT ctx) { 69 super(ctx); 70 71 queryMethod = new ParamsMethod(getClass(), QUERY_METHOD_NAME, Object.class); 72 } 73 74 @Override 75 public final RETURN query(VariableContext params) { 76 try { 77 return queryMethod.invoke(this, params); 78 } catch (InvocationTargetException ex) { 79 String thrownExceptionName = ex.getTargetException().getClass().getSimpleName(); 80 String msg = MessageFormat.format("{0} method has thrown an exception {1}", QUERY_METHOD_NAME, thrownExceptionName); 81 82 throw new MethodException(msg, ex.getTargetException()); 83 } 84 } 85 }