package eis.eis2java.handlers;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.Map;
import eis.eis2java.exception.TranslationException;
import eis.eis2java.translation.Translator;
import eis.eis2java.util.EIS2JavaUtil;
import eis.exceptions.ActException;
import eis.exceptions.EntityException;
import eis.iilang.Action;
import eis.iilang.Parameter;
import eis.iilang.Percept;
/**
* Default implementation of EIS2Java action handling. When an action is called,
* the handler will call the associated action method on the agent.
*
* @author mpkorstanje
*
*/
public class DefaultActionHandler extends ActionHandler {
protected final Map<String, Method> actionMethods;
protected final Object entity;
public DefaultActionHandler(Object entity) throws EntityException {
this.entity = entity;
this.actionMethods = EIS2JavaUtil.processActionAnnotations(entity
.getClass());
}
/*
* (non-Javadoc)
*
* @see
* nl.tudelft.goal.EIS2Java.environment.ActionHandler#isSupportedByClass
* (eis.iilang.Action, java.lang.Class)
*/
@Override
public final boolean isSupportedByEntity(Action action) {
String actionName = EIS2JavaUtil.getNameOfAction(action);
return actionMethods.get(actionName) != null;
}
/*
* (non-Javadoc)
*
* @see
* nl.tudelft.goal.EIS2Java.environment.ActionHandler#performAction(java
* .lang.Object, eis.iilang.Action)
*/
@Override
public final Percept performAction(Action action) throws ActException {
String actionName = EIS2JavaUtil.getNameOfAction(action);
Method actionMethod = actionMethods.get(actionName);
if (actionMethod == null) {
throw new ActException(ActException.FAILURE,
"Entity does not support action: " + action);
}
// workaround/fix for an EIS issue. #1986.
try {
return performAction(entity, actionMethod, action);
} catch (Exception e) {
if (e instanceof ActException) {
throw (ActException) e;
}
throw new ActException(ActException.FAILURE, "execution of action "
+ action + "failed", e);
}
}
/**
* Performs the action method on the given method using the parameters. The
* returned {@link Percept} will have the same name as the action.
*
* @param entity
* The entity to perform the method on.
* @param method
* The method to invoke on the entity.
* @param action
* The action that is being performed.
* @return The percept generated by the action.
* @throws ActException
* if the action can not be performed for any reason.
*/
private Percept performAction(Object entity, Method method, Action action)
throws ActException {
Translator translator = Translator.getInstance();
Class<?>[] parameterTypes = method.getParameterTypes();
LinkedList<Parameter> parameters = action.getParameters();
Object[] arguments = new Object[parameters.size()];
// Doing it the hard way because LinkedList.get(index) sucks!
int i = 0;
for (Parameter parameter : parameters) {
try {
arguments[i] = translator.translate2Java(parameter,
parameterTypes[i]);
} catch (TranslationException e) {
throw new ActException(ActException.FAILURE, "Action "
+ action.getName() + " with parameters " + parameters
+ " failed to be translated", e);
}
i++;
}
Object returnValue;
try {
returnValue = method.invoke(entity, arguments);
} catch (IllegalArgumentException e) {
throw new ActException(ActException.FAILURE, "Action "
+ action.getName() + " with parameters " + parameters
+ " failed to execute", e);
} catch (IllegalAccessException e) {
throw new ActException(ActException.FAILURE, "Action "
+ action.getName() + " with parameters " + parameters
+ " failed to execute", e);
} catch (InvocationTargetException e) {
throw new ActException(ActException.FAILURE, "Action "
+ action.getName() + " with parameters " + parameters
+ " failed to execute", e.getTargetException());
}
if (returnValue == null) {
return null;
} else {
try {
return new Percept(action.getName(),
translator.translate2Parameter(returnValue));
} catch (TranslationException e) {
throw new ActException(ActException.FAILURE, "Action "
+ action.getName() + " with parameters " + parameters
+ " failed to return a proper failue", e);
}
}
}
@Override
public void reset() {
// nothing to reset here
}
}