View Javadoc

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&lt;AttackbotContext, Boolean&gt; {
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 (MethodException ex) {
79              String msg = MessageFormat.format("Method {1} of sense {0} has thrown an exception. ", this.getClass().getName(), QUERY_METHOD_NAME);
80              throw new MethodException(msg, ex);
81          } catch (InvocationTargetException ex) {
82              String thrownExceptionName = ex.getTargetException().getClass().getSimpleName();
83              String msg = MessageFormat.format("Method {1} of sense {0} has thrown an exception {2}", this.getClass().getName(), QUERY_METHOD_NAME, thrownExceptionName);
84  
85              throw new MethodException(msg, ex.getTargetException());
86          }
87      }
88  }