package jadex.micro;
import jadex.bridge.ComponentServiceContainer;
import jadex.bridge.DecouplingServiceInvocationInterceptor;
import jadex.bridge.IComponentAdapter;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IComponentListener;
import jadex.bridge.IComponentManagementService;
import jadex.bridge.IComponentStep;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.IMessageService;
import jadex.bridge.IModelInfo;
import jadex.bridge.MessageType;
import jadex.commons.Future;
import jadex.commons.IFuture;
import jadex.commons.concurrent.DefaultResultListener;
import jadex.commons.concurrent.DelegationResultListener;
import jadex.commons.concurrent.IResultListener;
import jadex.commons.service.CacheServiceContainer;
import jadex.commons.service.IInternalService;
import jadex.commons.service.IServiceContainer;
import jadex.commons.service.IServiceIdentifier;
import jadex.commons.service.IServiceProvider;
import jadex.commons.service.SServiceProvider;
import jadex.commons.service.clock.IClockService;
import jadex.commons.service.clock.ITimedObject;
import jadex.commons.service.clock.ITimer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
* Base class for application agents.
*/
public abstract class MicroAgent implements IMicroAgent, IInternalAccess
{
//-------- attributes --------
/** The agent interpreter. */
protected MicroAgentInterpreter interpreter;
/** The current timer. */
protected List timers;
//-------- constructors --------
/**
* Init the micro agent with the interpreter.
* @param interpreter The interpreter.
*/
public void init(MicroAgentInterpreter interpreter)
{
// System.out.println("Init: "+interpreter);
this.interpreter = interpreter;
this.timers = new ArrayList();
}
//-------- interface methods --------
/**
* Called once after agent creation.
*/
public void agentCreated()
{
}
/**
* Execute the functional body of the agent.
* Is only called once.
*/
public void executeBody()
{
}
/**
* Called, whenever a message is received.
* @param msg The message.
* @param mt The message type.
*/
public void messageArrived(Map msg, MessageType mt)
{
}
/**
* Called just before the agent is removed from the platform.
* @return The result of the component.
*/
public void agentKilled()
{
}
//-------- methods --------
/**
* Get the service container.
* @return The service container.
*/
public IServiceContainer createServiceContainer()
{
return new CacheServiceContainer(new ComponentServiceContainer(getAgentAdapter()), 25, 1*30*1000); // 30 secs cache expire
// return new ComponentServiceContainer(getAgentAdapter());
}
/**
* Get the service provider.
* @return The service provider.
*/
public IServiceProvider getServiceProvider()
{
return interpreter.getServiceProvider();
}
/**
* Test if the agent's execution is currently at one of the
* given breakpoints. If yes, the agent will be suspended by
* the platform.
* Available breakpoints can be specified in the
* micro agent meta info.
* @param breakpoints An array of breakpoints.
* @return True, when some breakpoint is triggered.
*/
public boolean isAtBreakpoint(String[] breakpoints)
{
return false;
}
/**
* Get the external access for this agent.
*/
public IExternalAccess getExternalAccess()
{
return new ExternalAccess(this, interpreter);
}
/**
* Get the parent component.
* @return The parent (if any).
*/
public IExternalAccess getParent()
{
return interpreter.getParent();
}
/**
* Get the agent adapter.
* @return The agent adapter.
*/
public IComponentAdapter getAgentAdapter()
{
return interpreter.getAgentAdapter();
}
/**
* Get the arguments.
* @return The arguments.
*/
public Map getArguments()
{
return interpreter.getArguments();
}
/**
* Set a result value.
* @param name The result name.
* @param value The result value.
*/
public void setResultValue(String name, Object value)
{
interpreter.setResultValue(name, value);
}
/**
* Get an argument.
* @param name The argument name.
* @return The value.
*/
public Object getArgument(String name)
{
return interpreter.getArguments()==null? null: interpreter.getArguments().get(name);
}
/**
* Get the configuration.
* @return the Configuration.
*/
public String getConfiguration()
{
return interpreter.getConfiguration();
}
/**
* Create a result listener that is executed as an agent step.
* @param listener The listener to be executed as an agent step.
*/
public IResultListener createResultListener(IResultListener listener)
{
return interpreter.createResultListener(listener);
}
/**
* Get the current time.
* @return The current time.
*/
public IFuture getTime()
{
final Future ret = new Future();
SServiceProvider.getService(getServiceProvider(), IClockService.class)
.addResultListener(createResultListener(new DefaultResultListener()
{
public void resultAvailable(Object source, Object result)
{
IClockService cs = (IClockService)result;
ret.setResult(new Long(cs.getTime()));
}
}));
return ret;
}
// for debugging.
protected long longtime = 0;
/**
* Wait for an specified amount of time.
* @param time The time.
* @param run The runnable.
*/
public IFuture waitFor(final long time, final IComponentStep run)
{
longtime = Math.max(longtime, time);
final Future ret = new Future();
SServiceProvider.getService(getServiceProvider(), IClockService.class)
.addResultListener(createResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
IClockService cs = (IClockService)result;
final ITimer[] ts = new ITimer[1];
ts[0] = cs.createTimer(time, new ITimedObject()
{
public void timeEventOccurred(long currenttime)
{
interpreter.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
timers.remove(ts[0]);
run.execute(ia);
return null;
}
public String toString()
{
return getComponentIdentifier().getLocalName()+".waitForDue("+time+")_#"+this.hashCode();
}
});
}
public String toString()
{
return getComponentIdentifier().getLocalName()+".waitForDue("+time+")_#"+this.hashCode();
}
});
timers.add(ts[0]);
ret.setResult(new TimerWrapper(ts[0]));
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
}));
return ret;
}
/**
* Wait for the next tick.
* @param time The time.
*/
public IFuture waitForTick(final IComponentStep run)
{
final Future ret = new Future();
SServiceProvider.getService(getServiceProvider(), IClockService.class)
.addResultListener(createResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
IClockService cs = (IClockService)result;
final ITimer[] ts = new ITimer[1];
ts[0] = cs.createTickTimer(new ITimedObject()
{
public void timeEventOccurred(final long currenttime)
{
interpreter.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
timers.remove(ts[0]);
run.execute(ia);
return null;
}
public String toString()
{
return "microagent.waitForTickDue()_#"+this.hashCode();
}
});
}
});
timers.add(ts[0]);
ret.setResult(new TimerWrapper(ts[0]));
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
}));
return ret;
}
/**
* Get the logger.
* @return The logger.
*/
public Logger getLogger()
{
return getAgentAdapter().getLogger();
}
/**
* Kill the agent.
*/
public IFuture killAgent()
{
final Future ret = new Future();
SServiceProvider.getService(getServiceProvider(), IComponentManagementService.class)
.addResultListener(createResultListener(new DefaultResultListener()
{
public void resultAvailable(Object source, Object result)
{
IComponentManagementService cms = (IComponentManagementService)result;
cms.destroyComponent(getComponentIdentifier()).addResultListener(new DelegationResultListener(ret));
}
}));
return ret;
}
/**
* Send a message.
* @param me The message content (name value pairs).
* @param mt The message type describing the content.
*/
public IFuture sendMessage(final Map me, final MessageType mt)
{
final Future ret = new Future();
SServiceProvider.getService(getServiceProvider(), IMessageService.class)
.addResultListener(createResultListener(new DefaultResultListener()
{
public void resultAvailable(Object source, Object result)
{
IMessageService ms = (IMessageService)result;
ms.sendMessage(me, mt, interpreter.getAgentAdapter().getComponentIdentifier(),
interpreter.getAgentModel().getClassLoader())
.addResultListener(createResultListener(new DelegationResultListener(ret)));
}
}));
return ret;
}
/**
* Create component identifier.
* @param name The name.
* @param local True for local name.
* @param addresses The addresses.
* @return The new component identifier.
*/
public IFuture createComponentIdentifier(String name)
{
return createComponentIdentifier(name, true, null);
}
/**
* Create component identifier.
* @param name The name.
* @param local True for local name.
* @param addresses The addresses.
* @return The new component identifier.
*/
public IFuture createComponentIdentifier(String name, boolean local)
{
return createComponentIdentifier(name, local, null);
}
/**
* Create component identifier.
* @param name The name.
* @param local True for local name.
* @param addresses The addresses.
* @return The new component identifier.
*/
public IFuture createComponentIdentifier(final String name, final boolean local, final String[] addresses)
{
final Future ret = new Future();
SServiceProvider.getService(getServiceProvider(), IComponentManagementService.class)
.addResultListener(createResultListener(new DefaultResultListener()
{
public void resultAvailable(Object source, Object result)
{
IComponentManagementService cms = (IComponentManagementService)result;
ret.setResult(cms.createComponentIdentifier(name, local, addresses));
}
}));
return ret;
}
/**
* Create a reply to this message event.
* @param msgeventtype The message event type.
* @return The reply event.
*/
public IFuture createReply(final Map msg, final MessageType mt)
{
final Future ret = new Future();
SServiceProvider.getService(getServiceProvider(), IMessageService.class)
.addResultListener(createResultListener(new DefaultResultListener()
{
public void resultAvailable(Object source, Object result)
{
IMessageService ms = (IMessageService)result;
ret.setResult(ms.createReply(msg, mt));
}
}));
return ret;
}
/**
* Get the agent name.
* @return The agent name.
*/
public String getAgentName()
{
return getComponentIdentifier().getLocalName();
}
/**
* Get the agent identifier.
* @return The agent identifier.
*/
public IComponentIdentifier getComponentIdentifier()
{
return interpreter.getAgentAdapter().getComponentIdentifier();
}
/**
* Schedule a step of the agent.
* May safely be called from external threads.
* @param step Code to be executed as a step of the agent.
* /
public void scheduleStep(ICommand step)
{
interpreter.scheduleStep(step);
}*/
/**
* Schedule a step of the agent.
* May safely be called from external threads.
* @param step Code to be executed as a step of the agent.
*/
public IFuture scheduleStep(IComponentStep step)
{
return interpreter.scheduleStep(step);
}
/**
* Add a service to the platform.
* If under the same name and type a service was contained,
* the old one is removed and shutdowned.
* @param service The service.
*/
public void addDirectService(IInternalService service)
{
((IServiceContainer)interpreter.getServiceProvider()).addService(service);
}
/**
* Add a service to the platform.
* If under the same name and type a service was contained,
* the old one is removed and shutdowned.
* @param service The service.
*/
public void addService(IInternalService service)
{
IInternalService proxyser = DecouplingServiceInvocationInterceptor
.createServiceProxy(getExternalAccess(), getAgentAdapter(), service);
((IServiceContainer)interpreter.getServiceProvider()).addService(proxyser);
}
/**
* Removes a service from the platform (shutdowns also the service).
* @param service The service.
*/
public void removeService(IServiceIdentifier sid)
{
((IServiceContainer)interpreter.getServiceProvider()).removeService(sid);
}
/**
* Start the service provider.
* /
public IFuture startServiceProvider()
{
return ((IServiceContainer)interpreter.getServiceProvider()).start();
}*/
/**
* Invoke a runnable later that is guaranteed
* to be executed on agent thread.
* /
// Use getExternalAccess().invokeLater() instead ->
* will not be executed as step of agent but as external entry.
public void invokeLater(Runnable run)
{
interpreter.getAgentAdapter().invokeLater(run);
}*/
/**
* Get the model of the component.
* @return The model.
*/
public IModelInfo getModel()
{
return interpreter.getAgentModel();
}
/**
* Get the children (if any).
* @return The children.
*/
public IFuture getChildren()
{
return interpreter.getAgentAdapter().getChildrenAccesses();
}
/**
* Kill the component.
*/
public IFuture killComponent()
{
return killAgent();
}
/**
* Add an component listener.
* @param listener The listener.
*/
public void addComponentListener(IComponentListener listener)
{
interpreter.addComponentListener(listener);
}
/**
* Remove a component listener.
* @param listener The listener.
*/
public void removeComponentListener(IComponentListener listener)
{
interpreter.removeComponentListener(listener);
}
//-------- helper classes --------
/**
* Wrap a timer and remove it from the agent when it is cancelled.
*/
protected class TimerWrapper implements ITimer
{
//-------- attributes --------
/** The wrapped timer. */
ITimer timer;
//-------- constructors--------
/**
* Wrap a timer.
*/
public TimerWrapper(ITimer timer)
{
this.timer = timer;
}
//-------- ITimer interface --------
public void cancel()
{
timers.remove(timer);
timer.cancel();
}
public long getNotificationTime()
{
return timer.getNotificationTime();
}
public ITimedObject getTimedObject()
{
return timer.getTimedObject();
}
public void setNotificationTime(long time)
{
timer.setNotificationTime(time);
}
public boolean equals(Object obj)
{
return timer.equals(obj);
}
public int hashCode()
{
return timer.hashCode();
}
public String toString()
{
return timer.toString();
}
}
}