All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almende.eve.agent.AgentHostDefImpl Maven / Gradle / Ivy

There is a newer version: 3.1.1
Show newest version
/*
 * Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
 * License: The Apache Software License, Version 2.0
 */
package com.almende.eve.agent;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.net.ProtocolException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.almende.eve.agent.annotation.ThreadSafe;
import com.almende.eve.agent.callback.AsyncCallbackQueue;
import com.almende.eve.agent.log.EventLogger;
import com.almende.eve.config.Config;
import com.almende.eve.event.EventsFactory;
import com.almende.eve.event.EventsInterface;
import com.almende.eve.monitor.ResultMonitorFactory;
import com.almende.eve.monitor.ResultMonitorFactoryInterface;
import com.almende.eve.scheduler.Scheduler;
import com.almende.eve.scheduler.SchedulerFactory;
import com.almende.eve.state.State;
import com.almende.eve.state.StateFactory;
import com.almende.eve.state.TypedKey;
import com.almende.eve.transport.TransportService;
import com.almende.util.ClassUtil;
import com.almende.util.ObjectCache;
import com.almende.util.TypeUtil;

/**
 * The Class AgentHostDefImpl.
 * 
 * @author Almende
 */
public final class AgentHostDefImpl extends AgentHost {
	
	private static final Logger																	LOG					= Logger.getLogger(AgentHostDefImpl.class
																															.getSimpleName());
	private final ConcurrentHashMap									transportServices	= new ConcurrentHashMap();
	private final ConcurrentHashMap>								callbacks			= new ConcurrentHashMap>();
	private StateFactory																		stateFactory		= null;
	private SchedulerFactory																	schedulerFactory	= null;
	private Config																				config				= null;
	private final EventLogger																	eventLogger			= new EventLogger(
																															this);
	private boolean																				doesShortcut		= true;
	private ExecutorService																		pool				= Executors
																															.newCachedThreadPool(Config
																																	.getThreadFactory());
	private final ConcurrentHashMap, WeakReference>>	refStore			= new ConcurrentHashMap, WeakReference>>();
	private static final String																	AGENTS				= "agents";
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getPool()
	 */
	@Override
	public ExecutorService getPool() {
		return pool;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#loadConfig(com.almende.eve.config.Config)
	 */
	@Override
	public void loadConfig(final Config config) {
		host.setConfig(config);
		if (config != null) {
			ObjectCache.get(AGENTS).configCache(config);
			// initialize all factories for state, transport, and scheduler
			// important to initialize in the correct order: cache first,
			// then the state and transport services, and lastly scheduler.
			host.setStateFactory(config);
			host.addTransportServices(config);
			host.setSchedulerFactory(config);
			host.addAgents(config);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#signalAgents(com.almende.eve.agent.
	 * AgentSignal)
	 */
	@Override
	public void signalAgents(final AgentSignal event) {
		if (stateFactory != null) {
			final Iterator iter = stateFactory.getAllAgentIds();
			if (iter != null) {
				while (iter.hasNext()) {
					try {
						final Agent agent = getAgent(iter.next());
						if (agent != null) {
							agent.signalAgent(event);
						}
					} catch (final Exception e) {
						LOG.log(Level.WARNING, "Couldn't signal agent.", e);
					}
				}
			}
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getAgent(java.lang.String)
	 */
	@Override
	public Agent getAgent(final String agentId) throws ClassNotFoundException,
			InstantiationException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException, IOException {
		
		if (agentId == null) {
			return null;
		}
		
		if (getStateFactory() == null) {
			return null;
		}
		
		// Check if agent is instantiated already, returning if it is:
		Agent agent = ObjectCache.get(AGENTS).get(agentId, Agent.class);
		if (agent != null) {
			return agent;
		}
		// No agent found, normal initialization:
		
		// load the State
		final State state = getStateFactory().get(agentId);
		if (state == null) {
			// agent does not exist
			return null;
		}
		state.init();
		
		// read the agents class name from state
		final Class agentType = state.getAgentType();
		if (agentType == null) {
			LOG.warning("Cannot instantiate agent. "
					+ "Class information missing in the agents state "
					+ "(agentId='" + agentId + "')");
			return null;
		}
		
		if (!Agent.class.isAssignableFrom(agentType)) {
			// Found state info not representing an Agent, like e.g. TokenStore
			// or CookieStore.
			return null;
		}
		
		// instantiate the agent
		agent = (Agent) agentType.getConstructor().newInstance();
		agent.constr(this, state);
		agent.signalAgent(new AgentSignal(AgentSignal.INIT));
		
		// If allowed, cache agent:
		if (agentType.isAnnotationPresent(ThreadSafe.class)
				&& agentType.getAnnotation(ThreadSafe.class).value()) {
			ObjectCache.get(AGENTS).put(agentId, agent);
		}
		
		return agent;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#createAgentProxy(com.almende.eve.agent
	 * .AgentInterface, java.net.URI, java.lang.Class)
	 */
	@Override
	public  T createAgentProxy(
			final AgentInterface sender, final URI receiverUrl,
			final Class agentInterface) {
		
		// TODO: In the new model the proxy agents need to have an adres as
		// well! This will enforce usage of the agentCache!
		final String proxyId = "proxy_"
				+ (sender != null ? sender.getId() + "_" : "")
				+ agentInterface.getCanonicalName().replace(' ', '_');
		
		T proxy = ObjectCache.get(AGENTS).get(proxyId, agentInterface);
		if (proxy != null) {
			return proxy;
		}
		final AgentProxyFactory pf = new AgentProxyFactory(this);
		proxy = pf.genProxy(sender, receiverUrl, agentInterface, proxyId);
		
		ObjectCache.get(AGENTS).put(proxyId, proxy);
		
		return proxy;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#createAsyncAgentProxy(com.almende.eve
	 * .agent.AgentInterface, java.net.URI, java.lang.Class)
	 */
	@Override
	public  AsyncProxy createAsyncAgentProxy(
			final AgentInterface sender, final URI receiverUrl,
			final Class agentInterface) {
		return new AsyncProxy(createAgentProxy(sender, receiverUrl,
				agentInterface));
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#createAgent(java.lang.String,
	 * java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public  T createAgent(final String agentType,
			final String agentId) throws InstantiationException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, ClassNotFoundException, IOException {
		Class clazz = Class.forName(agentType);
		if (ClassUtil.hasSuperClass(clazz, Agent.class)) {
			return createAgent((Class) clazz, agentId);
		} else {
			return (T) createAspectAgent(clazz, agentId);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#createAgent(java.lang.Class,
	 * java.lang.String)
	 */
	@Override
	public  T createAgent(final Class agentType,
			final String agentId) throws InstantiationException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, IOException {
		
		// create the state
		final State state = getStateFactory().create(agentId);
		state.setAgentType(agentType);
		state.init();
		
		// instantiate the agent
		final T agent = agentType.getConstructor().newInstance();
		agent.constr(this, state);
		agent.signalAgent(new AgentSignal(AgentSignal.CREATE));
		agent.signalAgent(new AgentSignal(AgentSignal.INIT));
		
		// Cache agent if allowed
		if (agentType.isAnnotationPresent(ThreadSafe.class)
				&& agentType.getAnnotation(ThreadSafe.class).value()) {
			ObjectCache.get(AGENTS).put(agentId, agent);
		}
		
		return agent;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#createAspectAgent(java.lang.Class,
	 * java.lang.String)
	 */
	@Override
	public  AspectAgent createAspectAgent(
			final Class aspect, final String agentId)
			throws InstantiationException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException, IOException {
		
		@SuppressWarnings("unchecked")
		final AspectAgent result = createAgent(AspectAgent.class, agentId);
		result.init(aspect);
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#deleteAgent(java.lang.String)
	 */
	@Override
	public void deleteAgent(final String agentId) {
		if (agentId == null) {
			return;
		}
		Agent agent = null;
		try {
			agent = getAgent(agentId);
		} catch (final Exception e) {
			LOG.log(Level.WARNING, "Couldn't get agent to delete.", e);
		}
		if (agent != null) {
			if (getScheduler(agent) != null) {
				schedulerFactory.destroyScheduler(agentId);
			}
			try {
				// get the agent and execute the delete method
				agent.signalAgent(new AgentSignal(AgentSignal.DESTROY));
				agent.signalAgent(new AgentSignal(AgentSignal.DELETE));
				ObjectCache.get(AGENTS).delete(agentId);
				agent = null;
			} catch (final Exception e) {
				LOG.log(Level.WARNING, "Error deleting agent:" + agentId, e);
			}
		}
		// delete the state, even if the agent.destroy or agent.delete
		// failed.
		getStateFactory().delete(agentId);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#hasAgent(java.lang.String)
	 */
	@Override
	public boolean hasAgent(final String agentId) {
		return getStateFactory().exists(agentId);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getEventLogger()
	 */
	@Override
	public EventLogger getEventLogger() {
		return eventLogger;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#receive(java.lang.String,
	 * java.lang.Object, java.net.URI, java.lang.String)
	 */
	@Override
	public void receive(final String receiverId, final Object message,
			final URI senderUri, final String tag) throws IOException {
		try {
			AgentInterface receiver = getAgent(receiverId);
			
			if (receiver == null) {
				// Check if there might be a proxy in the objectcache:
				receiver = ObjectCache.get(AGENTS).get(receiverId,
						AgentInterface.class);
			}
			if (receiver != null) {
				receiver.receive(message, senderUri, tag);
			} else {
				throw new Exception();
			}
		} catch (final Exception e) {
			LOG.log(Level.WARNING, "Couldn't getAgent(" + receiverId + ")", e);
			throw new IOException(e);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#sendAsync(java.net.URI,
	 * java.lang.Object, com.almende.eve.agent.AgentInterface, java.lang.String)
	 */
	@Override
	public void sendAsync(final URI receiverUrl, final Object message,
			final AgentInterface sender, final String tag) throws IOException {
		final String receiverId = getAgentId(receiverUrl);
		final String protocol = receiverUrl.getScheme();
		if (("local".equals(protocol)) || (doesShortcut && receiverId != null)) {
			// local shortcut
			URI senderUri = null;
			if (sender != null) {
				senderUri = getSenderUrl(sender.getId(), receiverUrl);
			}
			receive(receiverId, message, senderUri, tag);
		} else {
			TransportService service = null;
			URI senderUri = null;
			if (sender != null) {
				senderUri = getSenderUrl(sender.getId(), receiverUrl);
			}
			service = getTransportService(protocol);
			if (service != null) {
				// TODO: message should already be a String?
				service.sendAsync(senderUri, receiverUrl, message.toString(),
						tag);
			} else {
				throw new ProtocolException(
						"No transport service configured for protocol '"
								+ protocol + "'.");
			}
		}
	}
	
	// TODO: change to URI en create a protocol->transport map in agentHost
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getAgentId(java.lang.String)
	 */
	@Override
	public String getAgentId(final URI agentUrl) {
		if (agentUrl.getScheme().startsWith("local")) {
			return agentUrl.toString().replaceFirst("local:/?/?", "");
		}
		for (final TransportService service : transportServices.values()) {
			String agentId = service.getAgentId(agentUrl);
			if (agentId != null) {
				return agentId;
			}
		}
		return null;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getSenderUrl(java.lang.String,
	 * java.net.URI)
	 */
	@Override
	public URI getSenderUrl(final String agentId, final URI receiverUrl) {
		if (receiverUrl.getScheme().equals("local")) {
			return URI.create("local:" + agentId);
		}
		for (final TransportService service : transportServices.values()) {
			final List protocols = service.getProtocols();
			for (final String protocol : protocols) {
				if (receiverUrl.getScheme().equals(protocol)) {
					return service.getAgentUrl(agentId);
				}
			}
		}
		LOG.warning("Couldn't find sender URL for:" + agentId + " | "
				+ receiverUrl.toASCIIString());
		return null;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getRef(java.lang.String,
	 * com.almende.eve.state.TypedKey)
	 */
	@Override
	public  T getRef(final String agentId, final TypedKey key) {
		final ConcurrentHashMap, WeakReference> objects = refStore
				.get(agentId);
		if (objects != null) {
			return TypeUtil.inject(objects.get(key).get(), key.getType());
		}
		
		return null;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#putRef(java.lang.String,
	 * com.almende.eve.state.TypedKey, java.lang.Object)
	 */
	@Override
	public  void putRef(final String agentId, final TypedKey key,
			final T value) {
		synchronized (refStore) {
			ConcurrentHashMap, WeakReference> objects = refStore
					.get(agentId);
			if (objects == null) {
				objects = new ConcurrentHashMap, WeakReference>();
			}
			objects.put(key, new WeakReference(value));
			refStore.put(agentId, objects);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#getStateFactoryFromConfig(com.almende
	 * .eve.config.Config, java.lang.String)
	 */
	@Override
	public StateFactory getStateFactoryFromConfig(final Config config,
			String configName) {
		StateFactory result = null;
		// get the class name from the config file
		// first read from the environment specific configuration,
		// if not found read from the global configuration
		
		String className = config.get(configName, "class");
		if (className == null) {
			if (!configName.equals("state")) {
				// Provide fallback to state if other type doesn't exist;
				configName = "state";
				className = config.get(configName, "class");
			}
			if (className == null) {
				throw new IllegalArgumentException("Config parameter '"
						+ config + ".class' missing in Eve configuration.");
			}
		}
		
		try {
			// get the class
			final Class stateClass = Class.forName(className);
			if (!ClassUtil.hasInterface(stateClass, StateFactory.class)) {
				throw new IllegalArgumentException("State factory class "
						+ stateClass.getName() + " must extend "
						+ State.class.getName());
			}
			
			// instantiate the state factory
			final Map params = config.get(configName);
			result = (StateFactory) stateClass.getConstructor(Map.class)
					.newInstance(params);
			
			LOG.info("Initialized state factory: " + result.toString());
		} catch (final Exception e) {
			LOG.log(Level.WARNING, "", e);
		}
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#setStateFactory(com.almende.eve.config
	 * .Config)
	 */
	@Override
	public void setStateFactory(final Config config) {
		if (stateFactory != null) {
			LOG.warning("Not loading statefactory from config, there is already a statefactory available.");
			return;
		}
		
		setStateFactory(getStateFactoryFromConfig(config, "state"));
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#addAgents(com.almende.eve.config.Config)
	 */
	@Override
	public void addAgents(final Config config) {
		final Map agents = config.get("bootstrap", AGENTS);
		if (agents != null) {
			for (final Entry entry : agents.entrySet()) {
				final String agentId = entry.getKey();
				final String agentType = entry.getValue();
				try {
					Agent agent = getAgent(agentId);
					if (agent == null) {
						// agent does not yet exist. create it
						agent = createAgent(agentType, agentId);
						LOG.info("Bootstrap created agent id=" + agentId
								+ ", type=" + agentType);
					}
				} catch (final Exception e) {
					LOG.log(Level.WARNING, "", e);
				}
			}
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#setStateFactory(com.almende.eve.state
	 * .StateFactory)
	 */
	@Override
	public void setStateFactory(final StateFactory stateFactory) {
		if (this.stateFactory != null) {
			LOG.warning("Not setting new stateFactory, there is already a factory initialized.");
			return;
		}
		this.stateFactory = stateFactory;
		host.signalAgents(new AgentSignal(
				AgentSignal.SETSTATEFACTORY, stateFactory));
		
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getStateFactory()
	 */
	@Override
	public StateFactory getStateFactory() {
		if (stateFactory == null) {
			LOG.warning("No state factory initialized.");
		}
		return stateFactory;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#setSchedulerFactory(com.almende.eve.config
	 * .Config)
	 */
	@Override
	public void setSchedulerFactory(final Config config) {
		// get the class name from the config file
		// first read from the environment specific configuration,
		// if not found read from the global configuration
		final String className = config.get("scheduler", "class");
		if (className == null) {
			throw new IllegalArgumentException(
					"Config parameter 'scheduler.class' missing in Eve configuration.");
		}
		
		// read all scheduler params (will be fed to the scheduler factory
		// on construction)
		final Map params = config.get("scheduler");
		
		try {
			// get the class
			final Class schedulerClass = Class.forName(className);
			if (!ClassUtil.hasInterface(schedulerClass, SchedulerFactory.class)) {
				throw new IllegalArgumentException("Scheduler class "
						+ schedulerClass.getName() + " must implement "
						+ SchedulerFactory.class.getName());
			}
			
			// initialize the scheduler factory
			final SchedulerFactory sf = (SchedulerFactory) schedulerClass
					.getConstructor(AgentHost.class, Map.class).newInstance(
							this, params);
			
			setSchedulerFactory(sf);
			
			LOG.info("Initialized scheduler factory: "
					+ sf.getClass().getName());
		} catch (final Exception e) {
			LOG.log(Level.WARNING, "", e);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#addTransportServices(com.almende.eve.
	 * config.Config)
	 */
	@Override
	public void addTransportServices(final Config config) {
		if (config == null) {
			final Exception e = new Exception("Configuration uninitialized");
			LOG.log(Level.WARNING, "", e);
			return;
		}
		
		// read global service params
		final List> allTransportParams = config
				.get("transport_services");
		if (allTransportParams != null) {
			int index = 0;
			for (final Map transportParams : allTransportParams) {
				String className = (String) transportParams.get("class");
				try {
					if (className != null) {
						
						// Recognize known classes by their short name,
						// and replace the short name for the full class path
						className = Config.map(className);
						// get class
						final Class transportClass = Class
								.forName(className);
						if (!ClassUtil.hasInterface(transportClass,
								TransportService.class)) {
							throw new IllegalArgumentException(
									"TransportService class "
											+ transportClass.getName()
											+ " must implement "
											+ TransportService.class.getName());
						}
						
						// initialize the transport service
						final TransportService transport = (TransportService) transportClass
								.getConstructor(AgentHost.class, Map.class)
								.newInstance(this, transportParams);
						
						// register the service with the agent factory
						addTransportService(transport);
					} else {
						LOG.warning("Cannot load transport service at index "
								+ index + ": no class defined.");
					}
				} catch (final Exception e) {
					LOG.log(Level.WARNING, "Cannot load service at index "
							+ index, e);
				}
				index++;
			}
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#addTransportService(com.almende.eve.transport
	 * .TransportService)
	 */
	@Override
	public void addTransportService(final TransportService transportService) {
		if (!transportServices.contains(transportService.getKey())) {
			transportServices.put(transportService.getKey(), transportService);
			LOG.info("Registered transport service: "
					+ transportService.toString());
			if (host != null) {
				host.signalAgents(new AgentSignal(
						AgentSignal.ADDTRANSPORTSERVICE, transportService));
			}
		} else {
			LOG.warning("Not adding transport service, as it already exists.");
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#removeTransportService(com.almende.eve
	 * .transport.TransportService)
	 */
	@Override
	public void removeTransportService(final TransportService transportService) {
		transportServices.remove(transportService);
		LOG.info("Unregistered transport service "
				+ transportService.toString());
		host.signalAgents(new AgentSignal(
				AgentSignal.DELTRANSPORTSERVICE, transportService));
		
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getTransportServices()
	 */
	@Override
	public List getTransportServices() {
		// TODO: check efficiency of this method, is there something simpler?
		return Collections.list(Collections.enumeration(transportServices
				.values()));
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#getTransportServices(java.lang.String)
	 */
	@Override
	public List getTransportServices(final String protocol) {
		final List filteredServices = new ArrayList();
		
		for (final TransportService service : transportServices.values()) {
			final List protocols = service.getProtocols();
			if (protocols.contains(protocol)) {
				filteredServices.add(service);
			}
		}
		
		return filteredServices;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#getTransportService(java.lang.String)
	 */
	@Override
	public TransportService getTransportService(final String protocol) {
		final List services = getTransportServices(protocol);
		if (services.size() > 0) {
			return services.get(0);
		}
		return null;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#setSchedulerFactory(com.almende.eve.scheduler
	 * .SchedulerFactory)
	 */
	@Override
	public void setSchedulerFactory(final SchedulerFactory schedulerFactory) {
		if (this.schedulerFactory != null) {
			LOG.warning("Replacing earlier schedulerFactory.");
		}
		this.schedulerFactory = schedulerFactory;
		host.signalAgents(new AgentSignal(
				AgentSignal.SETSCHEDULERFACTORY, schedulerFactory));
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#getScheduler(com.almende.eve.agent.Agent)
	 */
	@Override
	public Scheduler getScheduler(final Agent agent) {
		if (schedulerFactory == null) {
			return null;
		}
		return schedulerFactory.getScheduler(agent);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getCallbackQueue(java.lang.String,
	 * java.lang.Class)
	 */
	@Override
	public synchronized  AsyncCallbackQueue getCallbackQueue(
			final String id, final Class clazz) {
		// TODO: make this better!
		final TypeUtil> type = new TypeUtil>() {
		};
		AsyncCallbackQueue result = type.inject(callbacks.get(id));
		if (result == null) {
			result = new AsyncCallbackQueue();
			callbacks.put(id, result);
		}
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#setConfig(com.almende.eve.config.Config)
	 */
	@Override
	public void setConfig(final Config config) {
		this.config = config;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#getConfig()
	 */
	@Override
	public Config getConfig() {
		return config;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#isDoesShortcut()
	 */
	@Override
	public boolean isDoesShortcut() {
		return doesShortcut;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.agent.AgentHost#setDoesShortcut(boolean)
	 */
	@Override
	public void setDoesShortcut(final boolean doesShortcut) {
		this.doesShortcut = doesShortcut;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#getResultMonitorFactory(com.almende.eve
	 * .agent.AgentInterface)
	 */
	@Override
	public ResultMonitorFactoryInterface getResultMonitorFactory(
			final AgentInterface agent) {
		return new ResultMonitorFactory(agent);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.almende.eve.agent.AgentHost#getEventsFactory(com.almende.eve.agent
	 * .AgentInterface)
	 */
	@Override
	public EventsInterface getEventsFactory(final AgentInterface agent) {
		return new EventsFactory(agent);
	}
}