package nl.tudelft.bw4t.client.environment; import java.rmi.RemoteException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import eis.exceptions.ActException; import eis.exceptions.AgentException; import eis.exceptions.EntityException; import eis.iilang.Action; import eis.iilang.Percept; /** The ActionHandler Class handles the performAction function of the RemoteEnvironment. */ public final class ActionHandler { /** Should never be instantiated. */ private ActionHandler() { } /** * Handles the performAction function from the {@link RemoteEnvironment}. * All actions which are requested are routed through this function. * * @param agent * - The agent requesting the action. * @param action * - The {@link Action} being requested. * @param remoteEnvironment * - The RemoteEnvironment which should be acted upon. * @param entities * - The entities that should perform the action * @return A map of entity names -> {@link Percept} that have resulted by Execution of the action. * @throws ActException * The act exception is thrown if the action cannot be performed. * @throws AgentException * The agent exception is thrown if the agent is not registered * or does not have any entities assigned. */ public static Map<String, Percept> performActionDelegated(String agent, Action action, RemoteEnvironment remoteEnvironment, String... entities) throws ActException, AgentException { Set<String> associatedEntities = getAssociatedEntities(remoteEnvironment, action, agent); Set<String> targetEntities = getTargetEntities(associatedEntities, entities); checkSupportedEntities(entities, remoteEnvironment, action); return getActionPercept(targetEntities, remoteEnvironment, action); } /** * Gets the associated entities and performs a series of checks regarding prerequisites. * * @param remoteEnvironment * the remote environment which should be acted upon * @param action * the action being requested * @param agent * the agent requesting the action * @return the associated entities * which belong to the agent * @throws ActException the act exception * which is thrown if something is wrong with the prerequisites * @throws AgentException the agent exception * which is thrown if the environment is suddenly disconnected. */ private static Set<String> getAssociatedEntities(RemoteEnvironment remoteEnvironment, Action action, String agent) throws ActException, AgentException { /** Check to see if the agent is actually registered. */ if (!remoteEnvironment.getAgents().contains(agent)) { throw new ActException(ActException.NOTREGISTERED); } /** Check if the action is supported by the environment. */ if (!remoteEnvironment.isSupportedByEnvironment(action)) { throw new ActException(ActException.NOTSUPPORTEDBYENVIRONMENT); } /** Get a list of associated entities and target entities. */ Set<String> associatedEntities = remoteEnvironment.getAssociatedEntities(agent); if ((associatedEntities == null) || associatedEntities.isEmpty()) { throw new ActException(ActException.NOENTITIES); } return associatedEntities; } /** * Gets the targeted entities(The entities which should perform the {@link Action}). * * @param associatedEntities * - All the entities associated in the {@link RemoteEnvironment}. * @param entities * - The entities which should perform the action. * @return The set of entities which should perform the action. * @throws ActException * Thrown if the the entity is incorrect. */ private static Set<String> getTargetEntities(Set<String> associatedEntities, String... entities) throws ActException { if (entities.length == 0) { return associatedEntities; } Set<String> targetEntities = new HashSet<String>(entities.length); for (String entity : entities) { if (!associatedEntities.contains(entity)) { throw new ActException(ActException.WRONGENTITY); } targetEntities.add(entity); } return targetEntities; } /** * Check if the entity types and the entities are supported. * * @param entities * - The entities which need to be checked. * @param remoteEnvironment * - The {@link RemoteEnvironment} which is currently used. * @param action * - The {@link Action} which is requested to be performed. * @throws ActException * Thrown if the action is not support by the type of entity, or by the entity. */ private static void checkSupportedEntities(String[] entities, RemoteEnvironment remoteEnvironment, Action action) throws ActException { for (String entity : entities) { try { String type = remoteEnvironment.getType(entity); if (!remoteEnvironment.isSupportedByType(action, type)) { throw new ActException(ActException.NOTSUPPORTEDBYTYPE); } if (!remoteEnvironment.isSupportedByEntity(action, type)) { throw new ActException(ActException.NOTSUPPORTEDBYENTITY); } } catch (EntityException e) { throw new ActException("Can't get entity type", e); } } } /** * Perform the action on the server and get the resulting {@link Percept}{@code s}. * * @param targetEntities * - The entities which should perform the action. * @param remoteEnvironment * - The {@link RemoteEnvironment} which is acted upon. * @param action * - The {@link Action} to be performed. * @return The map of resulting percepts. * @throws ActException * Thrown if the server could not perform the action. */ private static Map<String, Percept> getActionPercept(Set<String> targetEntities, RemoteEnvironment remoteEnvironment, Action action) throws ActException { Map<String, Percept> actionPercepts = new HashMap<>(); for (String entity : targetEntities) { try { Percept percept = remoteEnvironment.performEntityAction(entity, action); if (percept != null) { actionPercepts.put(entity, percept); } } catch (RemoteException e) { throw new ActException(ActException.FAILURE, "performAction failed:", e); } } return actionPercepts; } }