Unverified Commit 342fea6f authored by Juon Kawakami's avatar Juon Kawakami 🥗
Browse files

init

parent 54f6cedf
package kernel;
import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import rescuecore2.config.Config;
import rescuecore2.messages.Command;
/**
A CommandFilter that chains together a set of filters.
*/
public class ChainedCommandFilter implements CommandFilter {
private List<CommandFilter> filters;
/**
Construct an empty ChainedCommandFilter.
*/
public ChainedCommandFilter() {
filters = new ArrayList<CommandFilter>();
}
/**
Add a CommandFilter to the chain.
@param filter The filter to add.
*/
public void addFilter(CommandFilter filter) {
filters.add(filter);
}
/**
Remove a CommandFilter from the chain.
@param filter The filter to remove.
*/
public void removeFilter(CommandFilter filter) {
filters.remove(filter);
}
@Override
public void initialise(Config config) {
for (CommandFilter next : filters) {
next.initialise(config);
}
}
@Override
public void filter(Collection<Command> commands, KernelState state) {
for (CommandFilter next : filters) {
next.filter(commands, state);
}
}
}
package kernel;
import rescuecore2.config.Config;
import rescuecore2.messages.Command;
import java.util.Collection;
/**
The CommandCollector gathers commands from agents.
*/
public interface CommandCollector {
/**
Collect all commands from agents.
@param agents The agents.
@param timestep The timestep.
@return All agent commands.
@throws InterruptedException If the thread is interrupted.
*/
Collection<Command> getAgentCommands(Collection<AgentProxy> agents, int timestep) throws InterruptedException;
/**
Initialise this command collector.
@param config The kernel configuration.
*/
void initialise(Config config);
}
package kernel;
import java.util.Collection;
import rescuecore2.config.Config;
import rescuecore2.messages.Command;
/**
An interface for allowing the kernel to filter out agent commands.
*/
public interface CommandFilter {
/**
Initialise this filter.
@param config The kernel configuration.
*/
void initialise(Config config);
/**
Filter a set of agent commands. Any illegal commands should be removed from the given collection.
@param commands The commands to filter. This collection should be modified to remove any illegal commands.
@param state The state of the kernel.
*/
void filter(Collection<Command> commands, KernelState state);
}
package kernel;
import java.util.Collection;
import rescuecore2.config.Config;
import rescuecore2.messages.Command;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.worldmodel.Entity;
/**
A model of communication. Implementers are responsible for determining what communications are received by each agent in the world.
*/
public interface CommunicationModel {
/**
Initialise this communication model.
@param config The kernel configuration.
@param world The world model.
*/
void initialise(Config config, WorldModel<? extends Entity> world);
/**
Process a set of agent commands and work out what communications each agent can hear.
@param time The current time.
@param agentCommands The set of all agent commands this timestep.
*/
void process(int time, Collection<? extends Command> agentCommands);
/**
Get the set of hear commands an agent can hear.
@param agent The agent controlled entity.
@return Set set of hear commands the agent can hear.
*/
Collection<Command> getHearing(Entity agent);
}
package kernel;
import java.util.Set;
import java.util.HashSet;
import java.util.Queue;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.HashMap;
import rescuecore2.config.Config;
import rescuecore2.connection.Connection;
import rescuecore2.connection.ConnectionException;
import rescuecore2.connection.ConnectionListener;
import rescuecore2.connection.ConnectionManagerListener;
import rescuecore2.messages.Message;
import rescuecore2.messages.control.KSAfterShocksInfo;
import rescuecore2.messages.control.VKConnect;
import rescuecore2.registry.Registry;
import rescuecore2.messages.control.VKAcknowledge;
import rescuecore2.messages.control.KVConnectOK;
import rescuecore2.messages.control.SKConnect;
import rescuecore2.messages.control.SKAcknowledge;
import rescuecore2.messages.control.KSConnectOK;
import rescuecore2.messages.control.AKConnect;
import rescuecore2.messages.control.AKAcknowledge;
import rescuecore2.messages.control.KAConnectError;
import rescuecore2.messages.control.KAConnectOK;
import rescuecore2.scenario.Scenario;
import rescuecore2.scenario.exceptions.UncompatibleScenarioException;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.GUIComponent;
import rescuecore2.log.Logger;
import kernel.ui.ComponentManagerGUI;
import javax.swing.JComponent;
/**
* Class that manages connecting components (agents, simulators, viewers) to the
* kernel.
*/
public class ComponentManager implements ConnectionManagerListener,
GUIComponent {
private static final int STARTING_ID = 1;
private static final int WAIT_TIME = 10000;
private Kernel kernel;
private ComponentManagerGUI gui;
// Entities that have no controller yet. Map from type to list of entities.
private Map<Integer, Queue<ControlledEntityInfo>> uncontrolledEntities;
// Connected agents
private Set<AgentAck> agentsToAcknowledge;
// Connected simulators
private Set<SimulatorAck> simsToAcknowledge;
private int nextID;
// Connected viewers
private Set<ViewerAck> viewersToAcknowledge;
// World information
private WorldModel<? extends Entity> world;
private Config config;
/** Lock objects. */
private final Object agentLock = new Object();
private final Object simLock = new Object();
private final Object viewerLock = new Object();
private final Object idLock = new Object();
private final Scenario scenario;
/**
* Create a ComponentManager.
*
* @param kernel
* The kernel.
* @param world
* The world model.
* @param config
* The kernel configuration.
*/
public ComponentManager(Kernel kernel, WorldModel<? extends Entity> world,
Config config, Scenario scenario) {
this.kernel = kernel;
this.world = world;
this.config = config;
this.scenario = scenario;
uncontrolledEntities = new HashMap<Integer, Queue<ControlledEntityInfo>>();
agentsToAcknowledge = new HashSet<AgentAck>();
simsToAcknowledge = new HashSet<SimulatorAck>();
viewersToAcknowledge = new HashSet<ViewerAck>();
nextID = STARTING_ID;
gui = new ComponentManagerGUI();
}
/**
* Register an agent-controlled entity.
*
* @param entity
* The entity that is agent-controlled.
* @param visibleOnStartup
* The set of entities that the agent should be sent on startup.
* If this is null then all entities will be sent.
* @param agentConfig
* A view of the system configuration that should be shared with
* the agent.
*/
public void registerAgentControlledEntity(Entity entity,
Collection<? extends Entity> visibleOnStartup, Config agentConfig) {
Logger.info("Agent controlled entity registered: " + entity);
synchronized (agentLock) {
Queue<ControlledEntityInfo> q = uncontrolledEntities.get(entity
.getURN());
if (q == null) {
q = new LinkedList<ControlledEntityInfo>();
uncontrolledEntities.put(entity.getURN(), q);
}
if (visibleOnStartup == null) {
visibleOnStartup = world.getAllEntities();
}
q.add(new ControlledEntityInfo(entity, visibleOnStartup,
agentConfig));
}
updateGUIUncontrolledAgents();
}
/**
* Wait for all agents to connect. This method will block until all agent
* entities have controllers.
*
* @throws InterruptedException
* If the thread is interrupted.
*/
public void waitForAllAgents() throws InterruptedException {
synchronized (agentLock) {
boolean done = false;
do {
done = true;
for (Entry<Integer, Queue<ControlledEntityInfo>> next : uncontrolledEntities
.entrySet()) {
if (!next.getValue().isEmpty()) {
done = false;
Logger.info("Waiting for " + next.getValue().size()
+ " entities of type " + next.getKey());
}
}
if (!agentsToAcknowledge.isEmpty()) {
done = false;
Logger.info("Waiting for " + agentsToAcknowledge.size()
+ " agents to acknowledge");
}
if (!done) {
agentLock.wait(WAIT_TIME);
}
} while (!done);
}
}
/**
* Wait until all simulators have acknowledged.
*
* @throws InterruptedException
* If the thread is interrupted.
*/
public void waitForAllSimulators() throws InterruptedException {
synchronized (simLock) {
while (!simsToAcknowledge.isEmpty()) {
simLock.wait(WAIT_TIME);
Logger.info("Waiting for " + simsToAcknowledge.size()
+ " simulators to acknowledge");
}
}
}
/**
* Wait until all viewers have acknowledged.
*
* @throws InterruptedException
* If the thread is interrupted.
*/
public void waitForAllViewers() throws InterruptedException {
synchronized (viewerLock) {
while (!viewersToAcknowledge.isEmpty()) {
viewerLock.wait(WAIT_TIME);
Logger.info("Waiting for " + viewersToAcknowledge.size()
+ " viewers to acknowledge");
}
}
}
@Override
public void newConnection(Connection c) {
c.addConnectionListener(new ComponentConnectionListener());
}
@Override
public JComponent getGUIComponent() {
return gui;
}
@Override
public String getGUIComponentName() {
return "Component manager";
}
private boolean agentAcknowledge(int requestID, EntityID agentID,
Connection c) {
synchronized (agentLock) {
for (AgentAck next : agentsToAcknowledge) {
if (next.requestID == requestID && next.agentID.equals(agentID)
&& next.connection == c) {
agentsToAcknowledge.remove(next);
kernel.addAgent(next.agent);
agentLock.notifyAll();
return true;
}
}
return false;
}
}
private boolean simAcknowledge(int requestID, int simulatorID, Connection c) {
synchronized (simLock) {
for (SimulatorAck next : simsToAcknowledge) {
if (next.requestID == requestID
&& next.simulatorID == simulatorID
&& next.connection == c) {
simsToAcknowledge.remove(next);
kernel.addSimulator(next.sim);
simLock.notifyAll();
return true;
}
}
return false;
}
}
private boolean viewerAcknowledge(int requestID, int viewerID, Connection c) {
synchronized (viewerLock) {
for (ViewerAck next : viewersToAcknowledge) {
if (next.requestID == requestID && next.viewerID == viewerID
&& next.connection == c) {
viewersToAcknowledge.remove(next);
kernel.addViewer(next.viewer);
viewerLock.notifyAll();
return true;
}
}
return false;
}
}
private int getNextSimulatorID() {
synchronized (idLock) {
return nextID++;
}
}
private int getNextViewerID() {
synchronized (idLock) {
return nextID++;
}
}
private ControlledEntityInfo findEntityToControl(List<Integer> types) {
Logger.debug("Finding entity to control. Requested types: " + types);
for (Integer next : types) {
Queue<ControlledEntityInfo> q = uncontrolledEntities.get(next);
Logger.debug("Uncontrolled entities of type " + next + ": " + q);
if (q != null) {
ControlledEntityInfo info = q.poll();
if (info != null) {
return info;
}
}
}
return null;
}
private void updateGUIUncontrolledAgents() {
List<String> data = new ArrayList<String>();
synchronized (agentLock) {
for (Queue<ControlledEntityInfo> q : uncontrolledEntities.values()) {
for (ControlledEntityInfo info : q) {
data.add(Registry.SYSTEM_REGISTRY.toPrettyName(info.entity.getURN()) + " " + info.entity.getID());
}
}
}
gui.updateUncontrolledAgents(data);
}
private void updateGUIAgentAck() {
List<String> data = new ArrayList<String>();
synchronized (agentLock) {
for (AgentAck ack : agentsToAcknowledge) {
data.add(ack.toString());
}
}
gui.updateAgentAck(data);
}
private void updateGUISimulatorAck() {
List<String> data = new ArrayList<String>();
synchronized (simLock) {
for (SimulatorAck ack : simsToAcknowledge) {
data.add(ack.toString());
}
}
gui.updateSimulatorAck(data);
}
private void updateGUIViewerAck() {
List<String> data = new ArrayList<String>();
synchronized (viewerLock) {
for (ViewerAck ack : viewersToAcknowledge) {
data.add(ack.toString());
}
}
gui.updateViewerAck(data);
}
private class ComponentConnectionListener implements ConnectionListener {
@Override
public void messageReceived(Connection connection, Message msg) {
if (msg instanceof AKConnect) {
handleAKConnect((AKConnect) msg, connection);
}
if (msg instanceof AKAcknowledge) {
handleAKAcknowledge((AKAcknowledge) msg, connection);
}
try {
if (msg instanceof SKConnect) {
handleSKConnect((SKConnect) msg, connection);
}
} catch (UncompatibleScenarioException e) {
e.printStackTrace();
}
if (msg instanceof SKAcknowledge) {
handleSKAcknowledge((SKAcknowledge) msg, connection);
}
if (msg instanceof VKConnect) {
handleVKConnect((VKConnect) msg, connection);
}
if (msg instanceof VKAcknowledge) {
handleVKAcknowledge((VKAcknowledge) msg, connection);
}
}
private void handleAKConnect(AKConnect connect, Connection connection) {
// Pull out the request ID and requested entity type list
int requestID = connect.getRequestID();
List<Integer> types = connect.getRequestedEntityTypes();
// See if we can find an entity for this agent to control.
Message reply = null;
Logger.debug("AKConnect received: " + types);
synchronized (agentLock) {
ControlledEntityInfo result = findEntityToControl(types);
if (result == null) {
Logger.debug("No suitable entities found");
// Send an error
reply = new KAConnectError(requestID, "No more agents");
} else {
Logger.debug("Found entity to control: " + result);
Entity entity = result.entity;
AgentProxy agent = new AgentProxy(connect.getAgentName(),
entity, connection);
agentsToAcknowledge.add(new AgentAck(agent, entity.getID(),
requestID, connection));
Logger.info("Agent '" + connect.getAgentName() + "' id "
+ entity.getID() + " (" + connection
+ " request ID " + requestID + ") connected");
// Send an OK
reply = new KAConnectOK(requestID, entity.getID(),
result.visibleSet, result.config);
}
}
if (reply != null) {
try {
connection.sendMessage(reply);
} catch (ConnectionException e) {
Logger.error("Error sending reply", e);
}
}
updateGUIUncontrolledAgents();
updateGUIAgentAck();
}
private void handleAKAcknowledge(AKAcknowledge msg,
Connection connection) {
int requestID = msg.getRequestID();
EntityID agentID = msg.getAgentID();
if (agentAcknowledge(requestID, agentID, connection)) {
Logger.info("Agent " + agentID + " (" + connection
+ " request ID " + requestID + ") acknowledged");
} else {
Logger.warn("Unexpected acknowledge from agent " + agentID
+ " (request ID " + requestID + ")");
}
updateGUIAgentAck();
}
private void handleSKConnect(SKConnect msg, Connection connection)
throws UncompatibleScenarioException {
int simID = getNextSimulatorID();
int requestID = msg.getRequestID();
Logger.info("Simulator '" + msg.getSimulatorName() + "' id "
+ simID + " (" + connection + " request ID " + requestID
+ ") connected");
SimulatorProxy sim = new SimulatorProxy(msg.getSimulatorName(),
simID, connection);
synchronized (simLock) {
simsToAcknowledge.add(new SimulatorAck(sim, simID, requestID,
connection));
}
// Send an OK
sim.send(Collections.singleton(new KSConnectOK(simID, requestID,
world.getAllEntities(), config)));
sendAdditionalInfoToSim(sim);
updateGUISimulatorAck();
}
/**
* Used to send info other than world model's to simulators. Information
* such as Aftershocks' properties and etc.
*
* @param sim
* @throws UncompatibleScenarioException
*/
private void sendAdditionalInfoToSim(SimulatorProxy sim)
throws UncompatibleScenarioException {
sim.send(Collections.singleton(new KSAfterShocksInfo(scenario)));
}
private void handleSKAcknowledge(SKAcknowledge msg,
Connection connection) {
int requestID = msg.getRequestID();
int simID = msg.getSimulatorID();
if (simAcknowledge(requestID, simID, connection)) {
Logger.info("Simulator " + simID + " (" + connection
+ " request ID " + requestID + ") acknowledged");
} else {
Logger.warn("Unexpected acknowledge from simulator " + simID
+ " (request ID " + requestID + ")");
}
updateGUISimulatorAck();
}
private void handleVKConnect(VKConnect msg, Connection connection) {
int requestID = msg.getRequestID();
int viewerID = getNextViewerID();
Logger.info("Viewer '" + msg.getViewerName() + "' id " + viewerID
+ " (" + connection + " request ID " + requestID
+ ") connected");
ViewerProxy viewer = new ViewerProxy(msg.getViewerName(), viewerID,
connection);
synchronized (viewerLock) {
viewersToAcknowledge.add(new ViewerAck(viewer, viewerID,
requestID, connection));
}
// Send an OK
viewer.send(Collections.singleton(new KVConnectOK(viewerID,
requestID, world.getAllEntities(), config)));
updateGUIViewerAck();
}
private void handleVKAcknowledge(VKAcknowledge msg,
Connection connection) {
int requestID = msg.getRequestID();
int viewerID = msg.getViewerID();
if (viewerAcknowledge(requestID, viewerID, connection)) {
Logger.info("Viewer " + viewerID + " (" + connection
+ " request ID " + requestID + ") acknowledged");
} else {
Logger.warn("Unexpected acknowledge from viewer " + viewerID
+ " (" + requestID + ")");
}
updateGUIViewerAck();
}
}
private static class AgentAck {
AgentProxy agent;
EntityID agentID;
int requestID;
Connection connection;
public AgentAck(AgentProxy agent, EntityID agentID, int requestID,
Connection c) {
this.agent = agent;
this.agentID = agentID;
this.requestID = requestID;
this.connection = c;
}
@Override
public String toString() {
return agent.getName() + ": "
+ Registry.SYSTEM_REGISTRY.toPrettyName(agent.getControlledEntity().getURN()) + " "
+ agent.getControlledEntity().getID() + "(" + connection
+ " request ID " + requestID + ")";
}
}
private static class SimulatorAck {
SimulatorProxy sim;
int simulatorID;
int requestID;
Connection connection;
public SimulatorAck(SimulatorProxy sim, int simID, int requestID,
Connection c) {
this.sim = sim;
this.simulatorID = simID;
this.requestID = requestID;
this.connection = c;
}
@Override
public String toString() {
return sim + " " + simulatorID + "(connection request ID "
+ requestID + ")";
}
}
private static class ViewerAck {
ViewerProxy viewer;
int viewerID;
int requestID;
Connection connection;
public ViewerAck(ViewerProxy viewer, int viewerID, int requestID,
Connection c) {
this.viewer = viewer;
this.viewerID = viewerID;
this.requestID = requestID;
this.connection = c;
}
@Override
public String toString() {
return viewer + " " + viewerID + "(connection request ID "
+ requestID + ")";
}
}
private static class ControlledEntityInfo {
Entity entity;
Collection<? extends Entity> visibleSet;
Config config;
public ControlledEntityInfo(Entity entity,
Collection<? extends Entity> visibleSet, Config config) {
this.entity = entity;
this.visibleSet = visibleSet;
this.config = config;
}
@Override
public String toString() {
return entity.toString();
}
}
}
package kernel;
import rescuecore2.config.Config;
import rescuecore2.log.Logger;
import rescuecore2.messages.Command;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
A CommandCollector that waits for any of a set of child CommandCollectors to return a result.
*/
public class CompositeCommandCollector implements CommandCollector {
private Set<CommandCollector> children;
private ExecutorService executorService;
/**
Construct a CompositeCommandCollector with no children.
*/
public CompositeCommandCollector() {
children = new HashSet<CommandCollector>();
}
@Override
public void initialise(Config config) {
for (CommandCollector next : children) {
next.initialise(config);
}
executorService = Executors.newFixedThreadPool(children.size());
}
@Override
public Collection<Command> getAgentCommands(Collection<AgentProxy> agents, int timestep) throws InterruptedException {
Collection<Command> result = new ArrayList<Command>();
if (agents.size() == 0) {
return result;
}
ExecutorCompletionService<Collection<Command>> service = new ExecutorCompletionService<Collection<Command>>(executorService);
Set<Future<Collection<Command>>> futures = new HashSet<Future<Collection<Command>>>();
for (CommandCollector next : children) {
futures.add(service.submit(new ChildCommandsFetcher(next, agents, timestep)));
}
try {
for (int i = 0; i < children.size(); ++i) {
try {
result = service.take().get();
break;
}
catch (ExecutionException e) {
Logger.error("Error while getting agent commands", e);
}
}
}
finally {
for (Future<Collection<Command>> next : futures) {
next.cancel(true);
}
}
return result;
}
/**
Add a child command collector.
@param child The child to add.
*/
public void addCommandCollector(CommandCollector child) {
children.add(child);
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append("CompositeCommandCollector [");
for (Iterator<CommandCollector> it = children.iterator(); it.hasNext();) {
result.append(it.next());
if (it.hasNext()) {
result.append(", ");
}
}
result.append("]");
return result.toString();
}
private static final class ChildCommandsFetcher implements Callable<Collection<Command>> {
private CommandCollector child;
private Collection<AgentProxy> agents;
private int timestep;
ChildCommandsFetcher(CommandCollector child, Collection<AgentProxy> agents, int timestep) {
this.child = child;
this.agents = agents;
this.timestep = timestep;
}
@Override
public Collection<Command> call() throws Exception {
return child.getAgentCommands(agents, timestep);
}
}
}
package kernel;
import rescuecore2.worldmodel.EntityID;
/**
Interface for objects that can generate new EntityIDs.
*/
public interface EntityIDGenerator {
/**
Create a new EntityID.
@return A new EntityID.
*/
EntityID generateID();
}
package kernel;
import rescuecore2.config.Config;
import rescuecore2.messages.Command;
import rescuecore2.log.Logger;
import java.util.Collection;
/**
A CommandFilter that ignores agent commands for some number of timesteps.
*/
public class FrozenAgentsCommandFilter implements CommandFilter {
private int freezeTime;
@Override
public void initialise(Config config) {
freezeTime = config.getIntValue(KernelConstants.IGNORE_AGENT_COMMANDS_KEY, 0);
}
@Override
public void filter(Collection<Command> commands, KernelState state) {
int time = state.getTime();
if (time < freezeTime) {
Logger.info("Ignoring early commands: " + time + " < " + freezeTime);
commands.clear();
}
}
}
package kernel;
import rescuecore2.config.Config;
import rescuecore2.components.ComponentLauncher;
import rescuecore2.connection.Connection;
import rescuecore2.connection.StreamConnection;
import rescuecore2.connection.ConnectionException;
import rescuecore2.misc.Pair;
/**
A class that knows how to connect components to the kernel using inline streams.
*/
public class InlineComponentLauncher extends ComponentLauncher {
private ComponentManager manager;
/**
Construct a new InlineComponentLauncher.
@param manager The component manager.
@param config The system configuration.
*/
public InlineComponentLauncher(ComponentManager manager, Config config) {
super(config);
this.manager = manager;
}
@Override
protected Connection makeConnection() throws ConnectionException {
Pair<Connection, Connection> connections = StreamConnection.createConnectionPair();
connections.first().setRegistry(getDefaultRegistry());
connections.first().startup();
manager.newConnection(connections.first());
return connections.second();
}
}
package kernel;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import rescuecore2.Constants;
import rescuecore2.Timestep;
import rescuecore2.config.Config;
import rescuecore2.log.CommandsRecord;
import rescuecore2.log.ConfigRecord;
import rescuecore2.log.EndLogRecord;
//import rescuecore2.log.FileLogWriter;
import rescuecore2.log.InitialConditionsRecord;
import rescuecore2.log.LogException;
import rescuecore2.log.LogWriter;
import rescuecore2.log.Logger;
import rescuecore2.log.PerceptionRecord;
import rescuecore2.log.RCRSLogFactory;
import rescuecore2.log.StartLogRecord;
import rescuecore2.log.UpdatesRecord;
import rescuecore2.messages.Command;
import rescuecore2.score.ScoreFunction;
//import rescuecore2.misc.gui.ChangeSetComponent;
import rescuecore2.worldmodel.ChangeSet;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.WorldModel;
/**
* The Robocup Rescue kernel.
*/
public class Kernel {
/** The log context for kernel log messages. */
public static final String KERNEL_LOG_CONTEXT = "kernel";
private Config config;
private Perception perception;
private CommunicationModel communicationModel;
private WorldModel<? extends Entity> worldModel;
private LogWriter log;
private Set<KernelListener> listeners;
private Collection<AgentProxy> agents;
private Collection<SimulatorProxy> sims;
private Collection<ViewerProxy> viewers;
private int time;
private Timestep previousTimestep;
private EntityIDGenerator idGenerator;
private CommandFilter commandFilter;
private TerminationCondition termination;
private ScoreFunction score;
private CommandCollector commandCollector;
private boolean isShutdown;
// private ChangeSetComponent simulatorChanges;
/**
* Construct a kernel.
*
* @param config The configuration to use.
* @param perception A perception calculator.
* @param communicationModel A communication model.
* @param worldModel The world model.
* @param idGenerator An EntityIDGenerator.
* @param commandFilter An optional command filter. This may be null.
* @param termination The termination condition.
* @param score The score function.
* @param collector The CommandCollector to use.
* @throws KernelException If there is a problem constructing the kernel.
*/
public Kernel(Config config, Perception perception,
CommunicationModel communicationModel,
WorldModel<? extends Entity> worldModel,
EntityIDGenerator idGenerator, CommandFilter commandFilter,
TerminationCondition termination, ScoreFunction score,
CommandCollector collector) throws KernelException {
try {
Logger.pushLogContext(KERNEL_LOG_CONTEXT);
this.config = config;
this.perception = perception;
this.communicationModel = communicationModel;
this.worldModel = worldModel;
this.commandFilter = commandFilter;
this.score = score;
this.termination = termination;
this.commandCollector = collector;
this.idGenerator = idGenerator;
listeners = new HashSet<KernelListener>();
agents = new TreeSet<AgentProxy>(new Comparator<AgentProxy>() {
@Override
public int compare(AgentProxy o1, AgentProxy o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
});
sims = new HashSet<SimulatorProxy>();
viewers = new HashSet<ViewerProxy>();
time = 0;
try {
String logName = config.getValue("kernel.logname");
Logger.info("Logging to " + logName);
File logFile = new File(logName);
if (logFile.getParentFile().mkdirs()) {
Logger.info("Created log directory: "
+ logFile.getParentFile().getAbsolutePath());
}
if (logFile.createNewFile()) {
Logger.info(
"Created log file: " + logFile.getAbsolutePath());
}
log = RCRSLogFactory.getLogWriter(logFile);
log.writeRecord(new StartLogRecord());
log.writeRecord(new InitialConditionsRecord(worldModel));
log.writeRecord(new ConfigRecord(config));
} catch (IOException e) {
throw new KernelException("Couldn't open log file for writing",
e);
} catch (LogException e) {
throw new KernelException("Couldn't open log file for writing",
e);
}
config.setValue(Constants.COMMUNICATION_MODEL_KEY,
communicationModel.getClass().getName());
config.setValue(Constants.PERCEPTION_KEY,
perception.getClass().getName());
// simulatorChanges = new ChangeSetComponent();
// Initialise
perception.initialise(config, worldModel);
communicationModel.initialise(config, worldModel);
commandFilter.initialise(config);
score.initialise(worldModel, config);
termination.initialise(config);
commandCollector.initialise(config);
isShutdown = false;
Logger.info("Kernel initialised");
Logger.info("Perception module: " + perception);
Logger.info("Communication module: " + communicationModel);
Logger.info("Command filter: " + commandFilter);
Logger.info("Score function: " + score);
Logger.info("Termination condition: " + termination);
Logger.info("Command collector: " + collector);
} finally {
Logger.popLogContext();
}
}
/**
* Get the kernel's configuration.
*
* @return The configuration.
*/
public Config getConfig() {
return config;
}
/**
* Get a snapshot of the kernel's state.
*
* @return A new KernelState snapshot.
*/
public KernelState getState() {
return new KernelState(getTime(), getWorldModel());
}
/**
* Add an agent to the system.
*
* @param agent The agent to add.
*/
public void addAgent(AgentProxy agent) {
synchronized (this) {
agents.add(agent);
}
fireAgentAdded(agent);
}
/**
* Remove an agent from the system.
*
* @param agent The agent to remove.
*/
public void removeAgent(AgentProxy agent) {
synchronized (this) {
agents.remove(agent);
}
fireAgentRemoved(agent);
}
/**
* Get all agents in the system.
*
* @return An unmodifiable view of all agents.
*/
public Collection<AgentProxy> getAllAgents() {
synchronized (this) {
return Collections.unmodifiableCollection(agents);
}
}
/**
* Add a simulator to the system.
*
* @param sim The simulator to add.
*/
public void addSimulator(SimulatorProxy sim) {
synchronized (this) {
sims.add(sim);
sim.setEntityIDGenerator(idGenerator);
}
fireSimulatorAdded(sim);
}
/**
* Remove a simulator from the system.
*
* @param sim The simulator to remove.
*/
public void removeSimulator(SimulatorProxy sim) {
synchronized (this) {
sims.remove(sim);
}
fireSimulatorRemoved(sim);
}
/**
* Get all simulators in the system.
*
* @return An unmodifiable view of all simulators.
*/
public Collection<SimulatorProxy> getAllSimulators() {
synchronized (this) {
return Collections.unmodifiableCollection(sims);
}
}
/**
* Add a viewer to the system.
*
* @param viewer The viewer to add.
*/
public void addViewer(ViewerProxy viewer) {
synchronized (this) {
viewers.add(viewer);
}
fireViewerAdded(viewer);
}
/**
* Remove a viewer from the system.
*
* @param viewer The viewer to remove.
*/
public void removeViewer(ViewerProxy viewer) {
synchronized (this) {
viewers.remove(viewer);
}
fireViewerRemoved(viewer);
}
/**
* Get all viewers in the system.
*
* @return An unmodifiable view of all viewers.
*/
public Collection<ViewerProxy> getAllViewers() {
synchronized (this) {
return Collections.unmodifiableCollection(viewers);
}
}
/**
* Add a KernelListener.
*
* @param l The listener to add.
*/
public void addKernelListener(KernelListener l) {
synchronized (listeners) {
listeners.add(l);
}
}
/**
* Remove a KernelListener.
*
* @param l The listener to remove.
*/
public void removeKernelListener(KernelListener l) {
synchronized (listeners) {
listeners.remove(l);
}
}
/**
* Get the current time.
*
* @return The current time.
*/
public int getTime() {
synchronized (this) {
return time;
}
}
/**
* Get the world model.
*
* @return The world model.
*/
public WorldModel<? extends Entity> getWorldModel() {
return worldModel;
}
/**
* Find out if the kernel has terminated.
*
* @return True if the kernel has terminated, false otherwise.
*/
public boolean hasTerminated() {
synchronized (this) {
return isShutdown || termination.shouldStop(getState());
}
}
/**
* Run a single timestep.
*
* @throws InterruptedException If this thread is interrupted during the
* timestep.
* @throws KernelException If there is a problem executing the
* timestep.
* @throws LogException If there is a problem writing the log.
*/
public void timestep()
throws InterruptedException, KernelException, LogException {
try {
Logger.pushLogContext(KERNEL_LOG_CONTEXT);
synchronized (this) {
if (time == 0) {
fireStarted();
}
if (isShutdown) {
return;
}
++time;
// Work out what the agents can see and hear (using the commands
// from the previous timestep).
// Wait for new commands
// Send commands to simulators and wait for updates
// Collate updates and broadcast to simulators
// Send perception, commands and updates to viewers
Timestep nextTimestep = new Timestep(time);
Logger.info("Timestep " + time);
Logger.debug("Sending agent updates");
long start = System.currentTimeMillis();
sendAgentUpdates(nextTimestep,
previousTimestep == null ? new HashSet<Command>()
: previousTimestep.getCommands());
long perceptionTime = System.currentTimeMillis();
Logger.debug("Waiting for commands");
Collection<Command> commands = waitForCommands(time);
nextTimestep.setCommands(commands);
log.writeRecord(new CommandsRecord(time, commands));
long commandsTime = System.currentTimeMillis();
Logger.debug("Broadcasting commands");
ChangeSet changes = sendCommandsToSimulators(time, commands);
// simulatorUpdates.show(changes);
nextTimestep.setChangeSet(changes);
log.writeRecord(new UpdatesRecord(time, changes));
long updatesTime = System.currentTimeMillis();
// Merge updates into world model
worldModel.merge(changes);
long mergeTime = System.currentTimeMillis();
Logger.debug("Broadcasting updates");
sendUpdatesToSimulators(time, changes);
sendToViewers(nextTimestep);
long broadcastTime = System.currentTimeMillis();
Logger.debug("Computing score");
double s = score.score(worldModel, nextTimestep);
long scoreTime = System.currentTimeMillis();
nextTimestep.setScore(s);
Logger.info("Timestep " + time + " complete");
Logger.debug("Score: " + s);
Logger.debug("Perception took : "
+ (perceptionTime - start) + "ms");
Logger.debug("Agent commands took : "
+ (commandsTime - perceptionTime) + "ms");
Logger.debug("Simulator updates took : "
+ (updatesTime - commandsTime) + "ms");
Logger.debug("World model merge took : "
+ (mergeTime - updatesTime) + "ms");
Logger.debug("Update broadcast took : "
+ (broadcastTime - mergeTime) + "ms");
Logger.debug("Score calculation took : "
+ (scoreTime - broadcastTime) + "ms");
Logger.debug("Total time : " + (scoreTime - start)
+ "ms");
fireTimestepCompleted(nextTimestep);
previousTimestep = nextTimestep;
Logger.debug("Commands: " + commands);
Logger.debug(
"Timestep commands: " + previousTimestep.getCommands());
}
} finally {
Logger.popLogContext();
}
}
/**
* Shut down the kernel. This method will notify all
* agents/simulators/viewers of the shutdown.
*/
public void shutdown() {
synchronized (this) {
if (isShutdown) {
return;
}
Logger.info("Kernel is shutting down");
ExecutorService service = Executors.newFixedThreadPool(
agents.size() + sims.size() + viewers.size());
List<Callable<Object>> callables = new ArrayList<Callable<Object>>();
for (AgentProxy next : agents) {
final AgentProxy proxy = next;
callables.add(Executors.callable(new Runnable() {
@Override
public void run() {
proxy.shutdown();
}
}));
}
for (SimulatorProxy next : sims) {
final SimulatorProxy proxy = next;
callables.add(Executors.callable(new Runnable() {
@Override
public void run() {
proxy.shutdown();
}
}));
}
for (ViewerProxy next : viewers) {
final ViewerProxy proxy = next;
callables.add(Executors.callable(new Runnable() {
@Override
public void run() {
proxy.shutdown();
}
}));
}
try {
service.invokeAll(callables);
} catch (InterruptedException e) {
Logger.warn("Interrupted during shutdown");
}
try {
log.writeRecord(new EndLogRecord());
log.close();
} catch (LogException e) {
Logger.error("Error closing log", e);
}
Logger.info("Kernel has shut down");
isShutdown = true;
fireShutdown();
}
}
private void sendAgentUpdates(Timestep timestep,
Collection<Command> commandsLastTimestep)
throws InterruptedException, KernelException, LogException {
perception.setTime(time);
communicationModel.process(time, commandsLastTimestep);
for (AgentProxy next : agents) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
ChangeSet visible = perception.getVisibleEntities(next);
Collection<Command> heard = communicationModel
.getHearing(next.getControlledEntity());
EntityID id = next.getControlledEntity().getID();
timestep.registerPerception(id, visible, heard);
log.writeRecord(new PerceptionRecord(time, id, visible, heard));
next.sendPerceptionUpdate(time, visible, heard);
}
}
private Collection<Command> waitForCommands(int timestep)
throws InterruptedException {
Collection<Command> commands = commandCollector.getAgentCommands(agents,
timestep);
Logger.debug("Raw commands: " + commands);
commandFilter.filter(commands, getState());
Logger.debug("Filtered commands: " + commands);
return commands;
}
/**
* Send commands to all simulators and return which entities have been
* updated by the simulators.
*/
private ChangeSet sendCommandsToSimulators(int timestep,
Collection<Command> commands) throws InterruptedException {
for (SimulatorProxy next : sims) {
next.sendAgentCommands(timestep, commands);
}
// Wait until all simulators have sent updates
ChangeSet result = new ChangeSet();
for (SimulatorProxy next : sims) {
Logger.debug("Fetching updates from " + next);
result.merge(next.getUpdates(timestep));
}
return result;
}
private void sendUpdatesToSimulators(int timestep, ChangeSet updates)
throws InterruptedException {
for (SimulatorProxy next : sims) {
next.sendUpdate(timestep, updates);
}
}
private void sendToViewers(Timestep timestep) {
for (ViewerProxy next : viewers) {
next.sendTimestep(timestep);
}
}
private Set<KernelListener> getListeners() {
Set<KernelListener> result;
synchronized (listeners) {
result = new HashSet<KernelListener>(listeners);
}
return result;
}
private void fireStarted() {
for (KernelListener next : getListeners()) {
next.simulationStarted(this);
}
}
private void fireShutdown() {
for (KernelListener next : getListeners()) {
next.simulationEnded(this);
}
}
private void fireTimestepCompleted(Timestep timestep) {
for (KernelListener next : getListeners()) {
next.timestepCompleted(this, timestep);
}
}
private void fireAgentAdded(AgentProxy agent) {
for (KernelListener next : getListeners()) {
next.agentAdded(this, agent);
}
}
private void fireAgentRemoved(AgentProxy agent) {
for (KernelListener next : getListeners()) {
next.agentRemoved(this, agent);
}
}
private void fireSimulatorAdded(SimulatorProxy sim) {
for (KernelListener next : getListeners()) {
next.simulatorAdded(this, sim);
}
}
private void fireSimulatorRemoved(SimulatorProxy sim) {
for (KernelListener next : getListeners()) {
next.simulatorRemoved(this, sim);
}
}
private void fireViewerAdded(ViewerProxy viewer) {
for (KernelListener next : getListeners()) {
next.viewerAdded(this, viewer);
}
}
private void fireViewerRemoved(ViewerProxy viewer) {
for (KernelListener next : getListeners()) {
next.viewerRemoved(this, viewer);
}
}
}
package kernel;
import rescuecore2.connection.Connection;
import rescuecore2.messages.Message;
import java.util.Collection;
/**
This class is the kernel interface to components (agents, viewers, simulators).
*/
public interface KernelComponent {
/**
Send a set of messages to this component.
@param m The messages to send.
*/
void send(Collection<? extends Message> m);
/**
Shut this component down.
*/
void shutdown();
/**
Get this component's connection.
@return The connection to the component.
*/
Connection getConnection();
/**
Get the name of this component.
@return The name of the component.
*/
String getName();
}
package kernel;
/**
Some useful constants for the kernel.
*/
public final class KernelConstants {
/** The config key for gis implementations. */
public static final String GIS_KEY = "kernel.gis";
/** The config key for perception implementations. */
public static final String PERCEPTION_KEY = "kernel.perception";
/** The config key for communication model implementations. */
public static final String COMMUNICATION_MODEL_KEY = "kernel.communication";
/** The config key for agent implementations. */
public static final String AGENTS_KEY = "kernel.agents";
/** The config key for simulator implementations. */
public static final String SIMULATORS_KEY = "kernel.simulators";
/** The config key for viewer implementations. */
public static final String VIEWERS_KEY = "kernel.viewers";
/** The config key for component implementations. */
public static final String COMPONENTS_KEY = "kernel.components";
/** Whether to run the kernel in inline-only mode. */
public static final String INLINE_ONLY_KEY = "kernel.inline-only";
/** The config key for ignoring agent commands at the start of the simulation. */
public static final String IGNORE_AGENT_COMMANDS_KEY = "kernel.agents.ignoreuntil";
private KernelConstants() {}
}
package kernel;
/**
Root of the kernel exception heirarchy.
*/
public class KernelException extends Exception {
/**
Construct a kernel exception with no information.
*/
public KernelException() {
super();
}
/**
Construct a kernel exception with an error message.
@param msg The error message.
*/
public KernelException(String msg) {
super(msg);
}
/**
Construct a kernel exception that was caused by another exception.
@param cause The cause of this exception.
*/
public KernelException(Throwable cause) {
super(cause);
}
/**
Construct a kernel exception with an error message and an underlying cause.
@param msg The error message.
@param cause The cause of this exception.
*/
public KernelException(String msg, Throwable cause) {
super(msg, cause);
}
}
package kernel;
import rescuecore2.Timestep;
/**
Interface for objects that are interested in kernel events.
*/
public interface KernelListener {
/**
Notification that the kernel has started the simulation.
@param kernel The kernel.
*/
void simulationStarted(Kernel kernel);
/**
Notification that the kernel has ended the simulation and shut down.
@param kernel The kernel.
*/
void simulationEnded(Kernel kernel);
/**
Notification that a timestep has been completed.
@param kernel The kernel.
@param time The timestep that has just been completed.
*/
void timestepCompleted(Kernel kernel, Timestep time);
/**
Notification that an agent has been added.
@param kernel The kernel.
@param agent The agent that was added.
*/
void agentAdded(Kernel kernel, AgentProxy agent);
/**
Notification that an agent has been removed.
@param kernel The kernel.
@param agent The agent that was removed.
*/
void agentRemoved(Kernel kernel, AgentProxy agent);
/**
Notification that a simulator has been added.
@param kernel The kernel.
@param simulator The simulator that was added.
*/
void simulatorAdded(Kernel kernel, SimulatorProxy simulator);
/**
Notification that a simulator has been removed.
@param kernel The kernel.
@param simulator The simulator that was removed.
*/
void simulatorRemoved(Kernel kernel, SimulatorProxy simulator);
/**
Notification that a viewer has been added.
@param kernel The kernel.
@param viewer The viewer that was added.
*/
void viewerAdded(Kernel kernel, ViewerProxy viewer);
/**
Notification that a viewer has been removed.
@param kernel The kernel.
@param viewer The viewer that was removed.
*/
void viewerRemoved(Kernel kernel, ViewerProxy viewer);
}
package kernel;
import rescuecore2.Timestep;
/**
Abstract class for objects that want to implement a subset of the KernelListener interface. All default method implementations do nothing.
*/
public class KernelListenerAdapter implements KernelListener {
@Override
public void simulationStarted(Kernel kernel) {}
@Override
public void simulationEnded(Kernel kernel) {}
@Override
public void timestepCompleted(Kernel kernel, Timestep time) {}
@Override
public void agentAdded(Kernel kernel, AgentProxy agent) {}
@Override
public void agentRemoved(Kernel kernel, AgentProxy agent) {}
@Override
public void simulatorAdded(Kernel kernel, SimulatorProxy simulator) {}
@Override
public void simulatorRemoved(Kernel kernel, SimulatorProxy simulator) {}
@Override
public void viewerAdded(Kernel kernel, ViewerProxy viewer) {}
@Override
public void viewerRemoved(Kernel kernel, ViewerProxy viewer) {}
}
package kernel;
import static rescuecore2.misc.java.JavaTools.instantiate;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.Collections;
import rescuecore2.misc.Pair;
import rescuecore2.config.Config;
import rescuecore2.components.Component;
import rescuecore2.components.Simulator;
import rescuecore2.components.Viewer;
import rescuecore2.components.Agent;
import rescuecore2.log.Logger;
/**
Container class for all kernel startup options.
*/
public class KernelStartupOptions {
private static final String AUTO_SUFFIX = ".auto";
private List<WorldModelCreator> worldOptions;
private List<Perception> perceptionOptions;
private List<CommunicationModel> commsOptions;
private Map<Simulator, Integer> sims;
private Map<Viewer, Integer> viewers;
private Map<Agent, Integer> agents;
private Map<Component, Integer> other;
private WorldModelCreator world;
private Perception perception;
private CommunicationModel comms;
/**
Create a KernelStartupOptions.
@param config The system configuration.
*/
public KernelStartupOptions(Config config) {
Pair<List<WorldModelCreator>, Integer> w = createOptions(config, KernelConstants.GIS_KEY, WorldModelCreator.class);
worldOptions = w.first();
world = worldOptions.get(w.second());
Pair<List<Perception>, Integer> p = createOptions(config, KernelConstants.PERCEPTION_KEY, Perception.class);
perceptionOptions = p.first();
perception = perceptionOptions.get(p.second());
Pair<List<CommunicationModel>, Integer> c = createOptions(config, KernelConstants.COMMUNICATION_MODEL_KEY, CommunicationModel.class);
commsOptions = c.first();
comms = commsOptions.get(c.second());
sims = createComponentOptions(config, KernelConstants.SIMULATORS_KEY, Simulator.class);
viewers = createComponentOptions(config, KernelConstants.VIEWERS_KEY, Viewer.class);
agents = createComponentOptions(config, KernelConstants.AGENTS_KEY, Agent.class);
other = createComponentOptions(config, KernelConstants.COMPONENTS_KEY, Component.class);
}
/**
Get the names of all components that should be started inline.
@return All inline component class names and the requested number of each.
*/
public Collection<Pair<String, Integer>> getInlineComponents() {
List<Pair<String, Integer>> result = new ArrayList<Pair<String, Integer>>();
for (Map.Entry<Simulator, Integer> next : sims.entrySet()) {
result.add(new Pair<String, Integer>(next.getKey().getClass().getName(), next.getValue()));
}
for (Map.Entry<Viewer, Integer> next : viewers.entrySet()) {
result.add(new Pair<String, Integer>(next.getKey().getClass().getName(), next.getValue()));
}
for (Map.Entry<Agent, Integer> next : agents.entrySet()) {
result.add(new Pair<String, Integer>(next.getKey().getClass().getName(), next.getValue()));
}
for (Map.Entry<Component, Integer> next : other.entrySet()) {
result.add(new Pair<String, Integer>(next.getKey().getClass().getName(), next.getValue()));
}
return result;
}
/**
Get the WorldModelCreator the kernel should use.
@return The selected WorldModelCreator.
*/
public WorldModelCreator getWorldModelCreator() {
return world;
}
/**
Set the WorldModelCreator the kernel should use.
@param creator The selected WorldModelCreator.
*/
public void setWorldModelCreator(WorldModelCreator creator) {
this.world = creator;
}
/**
Get the list of available WorldModelCreator implementations.
@return All known WorldModelCreators.
*/
public List<WorldModelCreator> getAvailableWorldModelCreators() {
return Collections.unmodifiableList(worldOptions);
}
/**
Get the Perception module the kernel should use.
@return The selected Perception.
*/
public Perception getPerception() {
return perception;
}
/**
Set the Perception module the kernel should use.
@param p The selected Perception.
*/
public void setPerception(Perception p) {
perception = p;
}
/**
Get the list of available Perception implementations.
@return All known Perceptions.
*/
public List<Perception> getAvailablePerceptions() {
return Collections.unmodifiableList(perceptionOptions);
}
/**
Get the CommunicationModel the kernel should use.
@return The selected CommunicationModel.
*/
public CommunicationModel getCommunicationModel() {
return comms;
}
/**
Set the CommunicationModel the kernel should use.
@param c The selected CommunicationModel.
*/
public void setCommunicationModel(CommunicationModel c) {
comms = c;
}
/**
Get the list of available CommunicationModel implementations.
@return All known CommunicationModels.
*/
public List<CommunicationModel> getAvailableCommunicationModels() {
return Collections.unmodifiableList(commsOptions);
}
/**
Get the list of available Simulator components.
@return All known Simulators.
*/
public Collection<Simulator> getAvailableSimulators() {
return Collections.unmodifiableSet(sims.keySet());
}
/**
Get the list of available Viewer components.
@return All known Viewers.
*/
public Collection<Viewer> getAvailableViewers() {
return Collections.unmodifiableSet(viewers.keySet());
}
/**
Get the list of available Agent components.
@return All known Agents.
*/
public Collection<Agent> getAvailableAgents() {
return Collections.unmodifiableSet(agents.keySet());
}
/**
Get the list of available components that are not simulators, viewers or agents.
@return All known Components that are not simulators, viewers or agents.
*/
public Collection<Component> getAvailableComponents() {
return Collections.unmodifiableSet(other.keySet());
}
/**
Get the number of instances of a type of component to start.
@param c The component type.
@return The number of instances to start.
*/
public int getInstanceCount(Component c) {
if (sims.containsKey(c)) {
return sims.get(c);
}
if (viewers.containsKey(c)) {
return viewers.get(c);
}
if (agents.containsKey(c)) {
return agents.get(c);
}
if (other.containsKey(c)) {
return other.get(c);
}
throw new IllegalArgumentException("Component " + c + " not recognised");
}
/**
Set the number of instances of a type of component to start.
@param c The component type.
@param count The number of instances to start.
*/
public void setInstanceCount(Component c, int count) {
if (c instanceof Simulator) {
sims.put((Simulator)c, count);
}
else if (c instanceof Viewer) {
viewers.put((Viewer)c, count);
}
else if (c instanceof Agent) {
agents.put((Agent)c, count);
}
else {
other.put(c, count);
}
}
private <T> Pair<List<T>, Integer> createOptions(Config config, String key, Class<T> expectedClass) {
List<T> instances = new ArrayList<T>();
int index = 0;
int selectedIndex = 0;
Logger.trace("Loading options: " + key);
List<String> classNames = config.getArrayValue(key);
String auto = config.getValue(key + AUTO_SUFFIX, null);
boolean autoFound = false;
for (String next : classNames) {
Logger.trace("Option found: '" + next + "'");
T t = instantiate(next, expectedClass);
if (t != null) {
instances.add(t);
if (next.equals(auto)) {
selectedIndex = index;
autoFound = true;
}
++index;
}
}
if (auto != null && !autoFound) {
Logger.warn("Could not find class " + auto + " in config key " + key + ". Values found: " + classNames);
}
return new Pair<List<T>, Integer>(instances, selectedIndex);
}
private <T> Map<T, Integer> createComponentOptions(Config config, String key, Class<T> expectedClass) {
Logger.trace("Loading component options: " + key);
Map<T, Integer> result = new HashMap<T, Integer>();
List<String> classNames = config.getArrayValue(key, "");
List<String> autoClassNames = config.getArrayValue(key + AUTO_SUFFIX, "");
Set<String> allClassNames = new HashSet<String>(classNames);
allClassNames.addAll(strip(autoClassNames));
for (String next : allClassNames) {
Logger.trace("Option found: '" + next + "'");
T t = instantiate(next, expectedClass);
if (t != null) {
int count = getStartCount(next, autoClassNames);
result.put(t, count);
}
}
return result;
}
private int getStartCount(String className, List<String> auto) {
for (String next : auto) {
if (next.startsWith(className)) {
int index = next.indexOf("*");
if (index == -1) {
return 1;
}
String arg = next.substring(index + 1);
if ("n".equals(arg)) {
return Integer.MAX_VALUE;
}
return Integer.parseInt(arg);
}
}
return 0;
}
private List<String> strip(List<String> autoClassNames) {
List<String> result = new ArrayList<String>(autoClassNames.size());
// Remove any trailing *n
for (String s : autoClassNames) {
int index = s.indexOf("*");
if (index != -1) {
result.add(s.substring(0, index));
}
else {
result.add(s);
}
}
return result;
}
}
package kernel;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.worldmodel.Entity;
/**
A class for obtaining information about the state of the kernel.
*/
public class KernelState {
private int time;
private WorldModel<? extends Entity> model;
/**
Construct a snapshot of the kernel state.
@param time The current time.
@param model The world model snapshot.
*/
public KernelState(int time, WorldModel<? extends Entity> model) {
this.time = time;
this.model = model;
}
/**
Get the current time.
@return The current time.
*/
public int getTime() {
return time;
}
/**
Get the world model.
@return The world model.
*/
public WorldModel<? extends Entity> getWorldModel() {
return model;
}
}
package kernel;
import rescuecore2.config.Config;
import java.util.Collection;
import java.util.Iterator;
/**
A TerminationCondition that returns true if any of its children return true.
*/
public class OrTerminationCondition implements TerminationCondition {
private Collection<TerminationCondition> children;
/**
Construct a new OrTerminationCondition.
@param children The child conditions. This must have at least one element.
*/
public OrTerminationCondition(Collection<TerminationCondition> children) {
if (children == null || children.size() == 0) {
throw new IllegalArgumentException("Must have at least one child");
}
this.children = children;
}
@Override
public boolean shouldStop(KernelState state) {
for (TerminationCondition next : children) {
if (next.shouldStop(state)) {
return true;
}
}
return false;
}
@Override
public void initialise(Config config) {
for (TerminationCondition next : children) {
next.initialise(config);
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (Iterator<TerminationCondition> it = children.iterator(); it.hasNext();) {
result.append(it.next());
if (it.hasNext()) {
result.append(" | ");
}
}
return result.toString();
}
}
package kernel;
import rescuecore2.config.Config;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.worldmodel.ChangeSet;
/**
Implementations of this interface are responsible for determining what entities/properties each agent can see.
*/
public interface Perception {
/**
Initialise this perception object.
@param config The kernel configuration.
@param world The world model.
*/
void initialise(Config config, WorldModel<? extends Entity> world);
/**
Determine what Entities are visible to a particular agent. The returned Entities should be copies of Entities in the ground-truth WorldModel. Only visible properties should have defined values.
@param agent The agent that is perceiving the world.
@return A collection of entities that the agent can perceive.
*/
ChangeSet getVisibleEntities(AgentProxy agent);
/**
Notify this perception object of the current time.
@param timestep The current timestep.
*/
void setTime(int timestep);
}
package kernel;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.dom4j.DocumentException;
import rescuecore2.Constants;
import rescuecore2.config.Config;
import rescuecore2.connection.Connection;
import rescuecore2.connection.ConnectionException;
import rescuecore2.connection.TCPConnection;
import rescuecore2.connection.ConnectionListener;
import rescuecore2.scenario.Scenario;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.worldmodel.DefaultWorldModel;
import rescuecore2.messages.Message;
import rescuecore2.messages.control.GKConnectOK;
import rescuecore2.messages.control.GKConnectError;
import rescuecore2.messages.control.KGConnect;
import rescuecore2.messages.control.KGAcknowledge;
import rescuecore2.log.Logger;
/**
* A WorldModelCreator that talks to a remote GIS.
*/
public class RemoteGISWorldModelCreator implements WorldModelCreator {
private int nextID;
@Override
public WorldModel<? extends Entity> buildWorldModel(Config config)
throws KernelException {
Logger.info("Connecting to remote GIS...");
DefaultWorldModel<Entity> world = DefaultWorldModel.create();
CountDownLatch latch = new CountDownLatch(1);
int gisPort = config.getIntValue(Constants.GIS_PORT_NUMBER_KEY,
Constants.DEFAULT_GIS_PORT_NUMBER);
Connection conn;
try {
conn = new TCPConnection(gisPort);
conn.addConnectionListener(new GISConnectionListener(latch, world));
conn.startup();
conn.sendMessage(new KGConnect(1));
} catch (IOException e) {
throw new KernelException("Couldn't connect to GIS", e);
} catch (ConnectionException e) {
throw new KernelException("Couldn't connect to GIS", e);
}
// Wait for a reply
try {
latch.await();
} catch (InterruptedException e) {
throw new KernelException("Interrupted while connecting to GIS", e);
}
conn.shutdown();
return world;
}
@Override
public String toString() {
return "Remote GIS";
}
@Override
public EntityID generateID() {
synchronized (this) {
return new EntityID(nextID++);
}
}
/**
* Listener for the GIS connection.
*/
private class GISConnectionListener implements ConnectionListener {
private CountDownLatch latch;
private DefaultWorldModel<Entity> model;
public GISConnectionListener(CountDownLatch latch,
DefaultWorldModel<Entity> model) {
this.latch = latch;
this.model = model;
}
public void messageReceived(Connection c, Message m) {
if (m instanceof GKConnectOK) {
try {
// Update the internal world model
model.removeAllEntities();
model.addEntities(((GKConnectOK) m).getEntities());
// Send an acknowledgement
c.sendMessage(new KGAcknowledge());
Logger.info("GIS connected OK");
// Trigger the countdown latch
latch.countDown();
nextID = 0;
for (Entity next : model) {
nextID = Math.max(nextID, next.getID().getValue());
}
++nextID;
} catch (ConnectionException e) {
Logger.error("RemoteGISWorldModelCreator.messageReceived",
e);
}
}
if (m instanceof GKConnectError) {
Logger.error("Error connecting to remote GIS: "
+ ((GKConnectError) m).getReason());
latch.countDown();
}
}
}
@Override
public Scenario getScenario(Config config) throws DocumentException{
return null;// TODO Salim implement
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment