package eis.eis2java.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import eis.eis2java.annotation.AsPercept; import eis.eis2java.handlers.DefaultPerceptHandler; import eis.exceptions.EntityException; import eis.exceptions.PerceiveException; /** * A module that prepares a batch of percepts. Percepts are gathered based on * {@link AsPercept} annotations. A batch can be collected using * {@link AllPerceptsModule#getAllPercepts()}. * * This class simplifies the implementation of the {@link AllPerceptsProvider} * by providing the functionality normally provided by the * {@link DefaultPerceptHandler}. * * Whenever the agent is ready to provide a new batch of percepts the agent * should call {@link #updatePercepts}. * * @author mpkorstanje * * */ public class AllPerceptsModule { /** * Methods that provide the percepts. */ private final Set<Method> perceptProviders; /** * Percepts pulled from bot. */ private final Map<Method, Object> perceptBatch = new HashMap<Method, Object>(); /** * Event percepts pulled from bot. */ private final Map<Method, List<Object>> eventPerceptBatch = new HashMap<Method, List<Object>>(); /** * Entity which we pull percepts from. */ private final Object entity; public AllPerceptsModule(Object entity) throws EntityException { this.entity = entity; // Setup percept providers. Class<?> clazz = entity.getClass(); perceptProviders = EIS2JavaUtil.processPerceptAnnotations(clazz); } /** * Calls all percept providers and puts the result in a new batch. * * @throws PerceiveException */ public synchronized void updatePercepts() throws PerceiveException { perceptBatch.clear(); for (Method method : perceptProviders) { AsPercept annotation = method.getAnnotation(AsPercept.class); String perceptName = annotation.name(); Object percept; try { percept = method.invoke(entity); } catch (IllegalArgumentException e) { throw new PerceiveException("Unable to update " + perceptName, e); } catch (IllegalAccessException e) { throw new PerceiveException("Unable to update " + perceptName, e); } catch (InvocationTargetException e) { throw new PerceiveException("Unable to update " + perceptName, e); } // Percept is event based, needs special handling. if (annotation.event()) { if (!eventPerceptBatch.containsKey(method)) { eventPerceptBatch.put(method, new ArrayList<Object>()); } List<Object> events = eventPerceptBatch.get(method); // Percept provides multiple items, add them independently. if (!annotation.multiplePercepts()) { throw new PerceiveException("Unable to update " + perceptName + " event percept must have multiplePercepts."); } if (!(percept instanceof Collection<?>)) { throw new PerceiveException("Unable to update " + perceptName + " return value must be a collection."); } events.addAll((Collection<?>) percept); } // Regular percept else { perceptBatch.put(method, percept); } } perceptBatch.putAll(eventPerceptBatch); } public synchronized Map<Method, Object> getAllPercepts() { // We can clear outstanding events. They'll be exported now. eventPerceptBatch.clear(); // Copy precept batch, we don't want to modify this one any more. return new HashMap<Method, Object>(perceptBatch); } }