com.almende.eve.agent.AgentHostDefImpl Maven / Gradle / Ivy
/*
* 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 extends T> 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
© 2015 - 2025 Weber Informatics LLC | Privacy Policy