package nl.tudelft.bw4t.client.environment;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import org.apache.log4j.Logger;
import eis.EnvironmentListener;
import eis.exceptions.AgentException;
import eis.exceptions.EntityException;
import eis.exceptions.RelationException;
import eis.iilang.EnvironmentState;
import nl.tudelft.bw4t.client.agent.BW4TAgent;
import nl.tudelft.bw4t.client.agent.HumanAgent;
import nl.tudelft.bw4t.client.startup.InitParam;
/**
* Class that can be registered to BW4TRemoteEnvironment as EnvironmentListener
* and will launch new agents when new entities are available This is needed
* when the BW4TRemoteEnvironment is runned stand-alone. Do not start this when
* running GOAL, as GOAL already is an environment runner and will associate
* agents to entities if entities appear.
*/
public class BW4TEnvironmentListener implements EnvironmentListener {
/** The log4j Logger which displays logs on console. */
private static final Logger LOGGER = Logger
.getLogger(BW4TEnvironmentListener.class);
/** {@link RemoteEnvironment} to listen to and interact with. */
private final RemoteEnvironment environment;
/**
* @param env
* {@link RemoteEnvironment} to listen to and interact with.
*/
public BW4TEnvironmentListener(RemoteEnvironment env) {
environment = env;
}
/**
* Handle a deleted entity
*
* @param entity
* - The deleted entity.
* @param agents
* - The list of associated agents.
*/
@Override
public void handleDeletedEntity(String entity, Collection<String> agents) {
for (String name : agents) {
BW4TAgent agent = environment.getRunningAgent(name);
if (agent != null) {
agent.setKilled();
environment.removeRunningAgent(agent);
}
}
environment.removeEntityController(entity);
}
/**
* Handle a free entity
*
* @param entity
* - The free entity.
* @param associatedEntities
* - The list of associated agents.
*/
@Override
public void handleFreeEntity(String entity,
Collection<String> associatedEntities) {
// Not used currently
}
/**
* Handle a new entity, load the human agent if it is of type human
* otherwise load the agent that was specified in the program argument or
* the default one (BW4TAgent).
*
* @param entity
* - The new entity.
*/
@Override
public void handleNewEntity(String entity) {
LOGGER.debug("Handeling new entity of the environment: " + entity);
try {
final int agentCount = environment.getAgents().size();
final boolean isHuman = "human".equals(environment.getType(entity));
BW4TAgent agent = null;
if (isHuman) {
agent = new HumanAgent("Human" + agentCount, environment);
} else {
agent = newAgent(InitParam.AGENTCLASS.getValue(), entity);
}
agent.registerEntity(entity);
environment.addRunningAgent(agent);
environment.associateEntity(agent.getAgentId(), entity);
agent.start();
} catch (InstantiationException | AgentException | RelationException
| EntityException e) {
LOGGER.error("Failed to handle new entity event.", e);
}
}
/**
* Creates a new agent.
*
* @param clazz
* @param entity
* @return Returns the newly created agent
* @throws InstantiationException
* @throws EntityException
*/
protected BW4TAgent newAgent(String clazz, String entity)
throws InstantiationException, EntityException {
try {
Class<? extends BW4TAgent> c = Class.forName(clazz).asSubclass(
BW4TAgent.class);
@SuppressWarnings("unchecked")
Constructor<BW4TAgent> cons = (Constructor<BW4TAgent>) c
.getConstructor(String.class, RemoteEnvironment.class);
// we use the entityId as name for the agent as well. #2761
BW4TAgent agent = cons.newInstance(entity, environment);
agent.setType(environment.getType(entity));
return agent;
} catch (InstantiationException | ClassNotFoundException
| NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new InstantiationException(e.getMessage());
}
}
/**
* Handles a state change.
*
* @param newState
* - The new state.
*/
@Override
public void handleStateChange(EnvironmentState newState) {
LOGGER.debug("Handeling new environment state: " + newState);
if (newState.equals(EnvironmentState.KILLED)) {
System.exit(0);
}
}
}