org.iids.aos.agent
Class Agent

java.lang.Object
  extended by org.iids.aos.agent.Agent
All Implemented Interfaces:
java.io.Serializable
Direct Known Subclasses:
AnonimizeClient, Anonimizer, Fish, FishTank, GlobeClient, GoogleClient, HelloWorld, MAClient, MathWsClient, MigratingAgent, MigratingServletAgent, MigratingWebServiceAgent, Receiver, Receiver, ResourceRegistry.ResourceRegistryAgent, Sender, WsaAgent, WSGatewayAgentModule.WSGatewayAgent

public abstract class Agent
extends java.lang.Object
implements java.io.Serializable

AgentScape agent interface. Every Java agent in AgentScape is a subclass of this Agent class, which wraps some of the AgentScape API calls for simplicity (effectively hiding details such as handles).

Access to the full API is still possible using the getApi() method. Note that methods in this API require an AgentHandle as an extra argument. For the AgentHandle, any handle belonging to the agent will generally do (except maybe for calls to receiveMessages(java.util.List, boolean).

For its most basic needs, the agent does generally not need to access the full API. Exceptions to that are the calls from the API that are not wrapped in this class, such as AgentContainer access, specific calls to the lookup service, and for creating new agents.

Once the agent is done (meaning that either a call to move(AgentScapeID) or kill() succeeded, or the agent run() method finished, the agent officially no longer exists, though if the agent has spawned other threads (if allowed by the security manager) these can continue to run, which is a little difficult to protect. In future, a security manager should be able to prevent most of these illegal access attempts. In any case, the agent's handles are no no longer valid, so the agent cannot call any methods of the AgentScape API.

Note that this class caches some information (like handles). If new handles are created using the API (ignoring the wrapper calls) then the information from calls such as getAgentHandles() is probably no longer correct. Using the API for such calls does not offer more functionality, and should be avoided.

All kinds of exceptions that can occur are wrapped inside an AgentScapeException for simplicity. For advanced error checking use Throwable.getCause().

Author:
Reinier Timmer (rjtimmer@cs.vu.nl), Michel Oey (michel@cs.vu.nl)
See Also:
Serialized Form

Field Summary
protected  AgentLog log
           
 
Constructor Summary
Agent()
           
 
Method Summary
 boolean agentRunning()
          See if (according to AgentScape) the agent is still running.
protected  void cleanUp()
          User definable cleanup of the agent before stopping.
 AgentHandle createAgentHandle()
          Create new communication handle for this agent.
 void deregister(AgentHandle handle, java.lang.String name)
           
 long getAgentCPUtime()
           
 java.util.List<AgentHandle> getAgentHandles()
          Obtain list of all agent handles.
 AgentScapeApi getApi()
          Obtain reference to AgentScape API, if needed.
 java.lang.String[] getArgs()
          Get startup arguments for the agent.
 org.mortbay.jetty.servlet.Context getContext()
          Return context in which servlets of this agents are executed.
 AgentScapeID getCurrentLocation()
          Obtain location ID where the agent currently resides.
 java.util.List<AgentScapeID> getLocations()
          List all available locations in this AgentScape world (lookup service).
static java.util.List<AgentScapeID> getLocations(AgentScapeApi api)
           
 AgentLog getLog()
          Get access to the agent's private log.
 AgentHandle getOwnerHandle()
          Obtain owner handle, which - by design - is associated with the owner (creator) of this agent.
 AgentHandle getPrimaryHandle()
          Obtain primary handle, which the agent can use to send/receive messages from this agent's owner and/or other agents.
 javax.servlet.http.HttpServlet getServlet(java.lang.String name)
          Get this agent's servlet by name.
 java.util.Set<java.lang.String> getServletNames()
          Lists the servlet names this agent has published.
 java.lang.Object getToken()
          Obtain token, so that access to the API is possible as well.
 void initAgent(AgentScapeApi _api, AgentScapeID loc, AgentHandle owner, AgentHandle primary, java.lang.String[] args)
          Initialisation, set agentscape API to contact.
 void kill()
          Kill the agent.
 java.util.Map<AgentHandle,AgentScapeID> lookup(java.lang.String name)
          Lookup handles of agents that have registered the String name.
static java.util.Map<AgentHandle,AgentScapeID> lookup(java.lang.String name, AgentScapeApi api)
           
static java.util.Map<AgentHandle,java.lang.String> lookupPublished(AgentScapeApi api, java.lang.String name)
           
 java.util.Map<AgentHandle,java.lang.String> lookupPublished(java.lang.String name)
          Lookup a value that was previously published under a certain name with the method publish.
 void move(AgentScapeID location)
          Move agent to remote location.
 void move(AgentScapeID location, java.lang.String leaseID)
          Move agent with custom lease negotiation.
 void publish(AgentHandle handle, java.lang.String name, java.lang.String value)
          Publish a value under a certain name.
 void publishServlet(java.lang.String name, javax.servlet.http.HttpServlet servlet)
          Publish a servlet for this Agent.
 Envelope receiveMessage(boolean block)
          Receive a message for this agent.
 Envelope receiveMessage(java.util.List<AgentHandle> handles, boolean block)
          Receive a message for this agent.
 java.util.List<Envelope> receiveMessages(boolean block)
          Receive messages for this agent.
 java.util.List<Envelope> receiveMessages(java.util.List<AgentHandle> handles, boolean block)
          Receive messages for this agent.
 void register(AgentHandle handle, java.lang.String name)
          Experimental, some simple agent registration and lookup methods.
 java.util.List<Envelope> removeAgentHandle(AgentHandle ah, boolean pickup)
          Remove existing communication handle for this agent.
abstract  void run()
          To be implemented by the agent.
 void sendMessage(Envelope env)
          Send a message to remote agent handle(s).
 void sendMessages(java.util.List<Envelope> envelopes)
          Send multiple messages to remote agent handle(s).
 void start()
          Start running the agent.
 void stopRunning()
          Notifies the agent that it can stop running.
 void waitForCompletion()
          Wait for this agent to be killed.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

log

protected AgentLog log
Constructor Detail

Agent

public Agent()
Method Detail

getLog

public AgentLog getLog()
Get access to the agent's private log. This log can be used for debugging purposes. Reading log messages can simply be done through the agent's log servlet, which is created for each agent by default.

Returns:
agent's private log

initAgent

public void initAgent(AgentScapeApi _api,
                      AgentScapeID loc,
                      AgentHandle owner,
                      AgentHandle primary,
                      java.lang.String[] args)
               throws AgentStartupException
Initialisation, set agentscape API to contact.

Usually called by the java agent runner, to set starting variables and such, so that the agent can actually get access to AgentScape. This function can be called only for each agent the host the agent currently resides. This prevents others from being able to re-init this agent.

TODO: exception when multiple initialization occurs!?

Parameters:
_api - Instance of (maybe remote) API to interact with.
loc - Current location of the agent.
owner - Handle of agent owner, can be used as a target for messages directed to the owner of the message, etc. This owner handle will not be part of the result of the getAgentHandles() method, as this handle is not really part of the agent itself. However, this is just a wrapper method for the API, which does not distinguish all different kinds of agent handles.
primary - The 'primary' agent handle is (just as the owner handle) created on agent creation time. It is passed to the agent owner, so that it at least knows one handle it can send control messages to. It is best for an agent to send messages from 'primary' to 'owner', and vice versa fot the agent owner.
args - Array of initial (String) arguments for the agent.
Throws:
AgentStartupException - If the agent cannot be initialized.

getArgs

public java.lang.String[] getArgs()
Get startup arguments for the agent.

Arguments can be supplied to the agent when starting it up, for example, as arguments to AgentScapeApi.startAgent(org.iids.aos.systemservices.communicator.structs.AgentHandle, boolean, java.lang.String...).

Returns:
String[] containing all the startup arguments.

getApi

public AgentScapeApi getApi()
Obtain reference to AgentScape API, if needed.

Usually, an agent does not need access to the full API, it can just use all the calls from the Agent superclass. The API does offer some more advanced features, such as lookup server access and read/write access to its agent container.

Returns:
An instance of the AgentScape API

getToken

public java.lang.Object getToken()
Obtain token, so that access to the API is possible as well.

NOTE: for future use only!

Returns:
Always returns null (unimplemented).

getOwnerHandle

public AgentHandle getOwnerHandle()
Obtain owner handle, which - by design - is associated with the owner (creator) of this agent. It can be used by this agent's owner to communicate with this Agent.

There is one special owner handle associated with each agent owner (though the AgentScape middleware does not explicitly see them as different parties). The owner handle can be used by an owner to receive messages from a specific agent. These messages are used as a private communication mechanism between owner and agent. Because each agent has an owner handle, an agent can always contact its owner using this handle. Because AgentScape itself does not recognize the difference between the owner handle and any other agent handle, one should be a little careful when using the API for receiving messages.

Messages to the owner should preferably originate from the primary handle, which is the only one that the owner is guaranteed to know (it was assigned at agent creation time). Even though the agent owner can get a list of all handles at any point during the agent's lifetime, using the primary handle avoids confusion.

Returns:
The owner handle.

getPrimaryHandle

public AgentHandle getPrimaryHandle()
Obtain primary handle, which the agent can use to send/receive messages from this agent's owner and/or other agents.

The primary handle is the handle where all messages from the owner will probably arrive. This is a convention, this does not need to be respected, though it will avoid some confusion if this model is used. Agents can create other handles, if so desired with createAgentHandle().

Returns:
The primary agent handle.

getAgentHandles

public java.util.List<AgentHandle> getAgentHandles()
                                            throws AgentScapeException
Obtain list of all agent handles.

This list contains all the current handles of this agent. These handles can be used in a call to receiveMessage(List,boolean) or receiveMessages(List,boolean). It does not include the owner handle, as the agent should really not use that handle for receiving messages.

Returns:
A list containing all handles valid for this agent.
Throws:
AgentScapeException - A problem obtaining the agent handles.

createAgentHandle

public AgentHandle createAgentHandle()
                              throws AgentScapeException
Create new communication handle for this agent.

Each agent can have multiple handles, each can be used for communication with other agents. If you desire anonimity, then it is best to use a separate handle for all the different parties your agent communicates with. An agent handle can never be resolved to the actual ID/name or another one of the agent handles by anyone else other than the middleware or the agent/owner itself.

Returns:
The newly created agent handle.
Throws:
AgentScapeException - If, for some reason, a new handle cannot be created.

removeAgentHandle

public java.util.List<Envelope> removeAgentHandle(AgentHandle ah,
                                                  boolean pickup)
                                           throws AgentScapeException
Remove existing communication handle for this agent.

You cannot and should not remove the primary or owner handle.

Each agent can have multiple handles, each can be used for communication with other agents. If you desire anonimity, then it is best to use a separate handle for all the different parties your agent communicates with. An agent handle can never be resolved to the actual ID/name or another one of the agent handles by anyone else than the middleware or the agent/owner itself.

Parameters:
ah - AgentHandle to be removed from this agent
pickup - if true, any undelivered envelopes to this handle will be returned.
Returns:
returns a list of undelivered envelopes to this handle if pickup is true.
Throws:
AgentScapeException - If, for some reason, a the handle cannot be removed.
See Also:
createAgentHandle()

getCurrentLocation

public AgentScapeID getCurrentLocation()
Obtain location ID where the agent currently resides.

Returns:
ID of the current location.

getLocations

public java.util.List<AgentScapeID> getLocations()
                                          throws AgentScapeException
List all available locations in this AgentScape world (lookup service).

A simple wrapper around a lookup service request, that returns a list of all the location IDs that are known at this specific point in time.

Returns:
A list of all available locations in this world.
Throws:
AgentScapeException - If there is a problem accessing the AgentScape API.

getLocations

public static java.util.List<AgentScapeID> getLocations(AgentScapeApi api)
                                                 throws AgentScapeException
Throws:
AgentScapeException

sendMessage

public void sendMessage(Envelope env)
                 throws AgentScapeException
Send a message to remote agent handle(s).

Agent information (such as sender/receiver) is present in the envelope. If all this information is correct, then the message will be delivered to the remote agent(s).

The sending agent can use any of its current existing handles (except for the owner-handle) as the source handle in the envelope.

The envelope can contain a list of target handles, in which case the envelope will be sent to all these handles (multi-cast).

The data in the envelope can be any serializable object.

To send a message to this agent's owner, use this agent's primary handle as source handle.

This method is MT-safe.

Parameters:
env - Envelope to send. Note that for this envelope, the source handle Envelope.getFromHandle() must match a local handle.
Throws:
AgentScapeException - If the message cannot be delivered.

sendMessages

public void sendMessages(java.util.List<Envelope> envelopes)
                  throws AgentScapeException
Send multiple messages to remote agent handle(s).

Agent information (such as sender/receiver) is present in the envelope. If all this information is correct, then the message will be delivered to the remote agent(s).

This method is MT-safe.

Parameters:
envelopes - Envelopes to send. Note that for each envelope env in this list, the handle Envelope.getFromHandle() must match a local handle.
Throws:
AgentScapeException - If the message cannot be delivered.
See Also:


receiveMessage

public Envelope receiveMessage(java.util.List<AgentHandle> handles,
                               boolean block)
                        throws AgentScapeException
Receive a message for this agent.

An agent can have multiple handles. Use this method to receive messages that were sent to any subset of these handles. This subset can be specified in the parameter handles. Any existing handle of this agent can be present in this list, except for the owner handle (the one returned by getOwnerHandle().

This method is MT-safe. However, a message will only be delivered _once_ (i.e., to one thread only) even if multiple threads are trying to receive messages for that particular handle.

Parameters:
handles - A list of handles to receive from. If handles==null then data is received from all currently existing handles of this agent (except the owner handle).
block - Block (true) while waiting for message to arrive or poll (false) for messages. If blocking, this call will return only if a message has been received for this handle, this agent handle has been removed, or until the agent has been removed from the host.
Returns:
A single message sent to the list of agent handles, or null if there was no pending message for this agent (and block was false.
Throws:
AgentScapeException - If there was any problem receiving the message.

receiveMessage

public Envelope receiveMessage(boolean block)
                        throws AgentScapeException
Receive a message for this agent.

Shortcut for receiveMessage(null,block).

Parameters:
block - Block (true) while waiting for message to arrive or poll (false) for messages.
Returns:
A single message sent to the list of agent handles, or null if there was no pending message for this agent (and block was false.
Throws:
AgentScapeException - If there was any problem receiving the message.
See Also:


receiveMessages

public java.util.List<Envelope> receiveMessages(java.util.List<AgentHandle> handles,
                                                boolean block)
                                         throws AgentScapeException
Receive messages for this agent.

Parameters:
handles - A list of handles to receive from. If this is null then data is received from all handles (except the owner handle) that are associated with this agent.

This method is MT-safe. However, a message will only be delivered _once_ (i.e., to one thread only) even if multiple threads are trying to receive messages for that particular handle.

block - Block (true) while waiting for message to arrive or poll (false) for messages.
Returns:
A list of messages sent to the list of agent handles, or null if there was no pending message for this agent (and block was false.
Throws:
AgentScapeException - If there was any problem receiving the messages.
See Also:


receiveMessages

public java.util.List<Envelope> receiveMessages(boolean block)
                                         throws AgentScapeException
Receive messages for this agent.

Shortcut for receiveMessages(null,block).

Parameters:
block - Block (if true) while waiting for message to arrive or poll (if false) for messages.
Returns:
A list of messages sent to the list of agent handles, or null if there was no pending message for this agent (and block was false.
Throws:
AgentScapeException - If there was any problem receiving the messages.
See Also:


cleanUp

protected void cleanUp()
User definable cleanup of the agent before stopping. This method is called by the method stopRunning(), which is called by AgentScape whenever the agent moves or is (being) killed. An Agent-developer can override this method to perform any cleanup necessary before the agent is stopped permanently, such as stopping any threads this agent has created or removing any windows that have been put on the screen.

This method may not throw any Exceptions.


stopRunning

public final void stopRunning()
Notifies the agent that it can stop running. The agent is not killed by this method (this may already have been done, or will happen sometime later). It effectively makes sure the agentRunning() method returns false (and thus, the method waitForCompletion() also returns).

This function is implicitly called after the kill() method or the move(org.iids.aos.systemservices.communicator.structs.AgentScapeID) method returns successfully. This method is called by the agent server, the Agent itself should never call this method, otherwise the kill() method does not work anymore (and you would need to call AgentScapeApi.killAgent(org.iids.aos.systemservices.communicator.structs.AgentHandle) from the main APi.

Bottom line: don't call this method from the agent directly. If you need to perform some clean-up before the agent stop, override the cleanUp() method, which will be called by AgentScape whenever stopRunning is executed.

See Also:
agentRunning(), waitForCompletion(), kill(), move(org.iids.aos.systemservices.communicator.structs.AgentScapeID), cleanUp()

kill

public final void kill()
                throws AgentScapeException
Kill the agent.

Calls the agent server, and instructs it to kill this agent. The agent itself is now no longer running on this host (though not all of its threads may have terminated).

Throws:
AgentScapeException - If the agent cannot be killed.

move

public void move(AgentScapeID location)
          throws AgentScapeException
Move agent to remote location. If this call is successful, the agent is now running on location location, and the local agent can stop running.

Currently there is no way for the middleware to make sure that the agent is actually done. For now, the agent is trusted to take care of stopping all threads (see cleanUp(). In future, the security manager could be used to track down all of the threads that are currently running on behalf of the agent (and only confirm migration once all threads have finished).

Parameters:
location - Destination location of the agent.
Throws:
AgentScapeException - If there was an error and the migration request could not be completed.

move

public void move(AgentScapeID location,
                 java.lang.String leaseID)
          throws AgentScapeException
Move agent with custom lease negotiation.

Parameters:
location - Target location
leaseID - Pre-negotiated lease
Throws:
AgentScapeException - If the migration fails

start

public final void start()
Start running the agent.

Probably called from the JavaAgentRunner, performs some initialisation before calling run() and cleanup after the agent has finished. As an agent programmer, you don't need to use this method.


run

public abstract void run()
To be implemented by the agent. This is the main method of the Agent. This method is called by AgentScape as soon as the agent starts.

Once this function finishes, the agent is done. This can be preceded by a successful call to move(AgentScapeID) if the agent should continue to run on another location. If no successful move was done beforehand, then the agent is removed from the location.

Note that it is assumed that, once an agent moved to another location, this method will finish soon afterwards. There is no protection against this (yet) however.

Any cleanup operations can be done by implementing cleanUp().

See Also:
cleanup, move

waitForCompletion

public void waitForCompletion()
Wait for this agent to be killed. This method will return either after someone called the kill() method (the owner, the agent itself, or maybe the agent server). It also returns whenever the run() method finishes (after which kill() is also implicitly called.

This is useful if the agent has multiple threads, and some of them need to wait until the agent completes. What it actually does is wait for the method agentRunning() to return false, so you can also check it yourself. For example, if you want to perform some function for as long as the agent lives, you can just use while (agentRunning()) { do_stuff(); }

See Also:
agentRunning

agentRunning

public boolean agentRunning()
See if (according to AgentScape) the agent is still running.

Returns:
A boolean value whether the agent is legally running on this host (if value = true), otherwise the AgentScape middleware has either killed or moved the agent, and its thread should stop.

See Also:
waitForCompletion

register

public void register(AgentHandle handle,
                     java.lang.String name)
              throws AgentScapeException
Experimental, some simple agent registration and lookup methods.

This can for now only be used to lookup and register agent names. Location names, agent addresses, etc cannot be handled by this method.

Also handles the automatic agent name re-registration during the course of the agent lifetime.

After the name is registered, it can be looked up up again. One can also obtain the current location of the agent handle (or should this be hidden?) using lookup(java.lang.String).

Note: a more generic version of this is publish.

Parameters:
handle - The handle which to register the name to
name - The name to associate with this handle
Throws:
AgentScapeException - If there is some problem in registering the handle/name.
See Also:
publish, lookup


deregister

public void deregister(AgentHandle handle,
                       java.lang.String name)
                throws AgentScapeException
Throws:
AgentScapeException

lookup

public java.util.Map<AgentHandle,AgentScapeID> lookup(java.lang.String name)
                                               throws AgentScapeException
Lookup handles of agents that have registered the String name.

Parameters:
name - The name to query the lookup service for.
Returns:
A map containing entries with the AgentHandle that registered the String name, as well as the location on which the agent resideded when it registered name.
Throws:
AgentScapeException - Problem performing lookup of registered name.
See Also:
register

lookup

public static final java.util.Map<AgentHandle,AgentScapeID> lookup(java.lang.String name,
                                                                   AgentScapeApi api)
                                                            throws AgentScapeException
Throws:
AgentScapeException
See Also:
lookup

publish

public void publish(AgentHandle handle,
                    java.lang.String name,
                    java.lang.String value)
             throws AgentScapeException
Publish a value under a certain name. Other agents can retrieve the value with the method lookupPublished.

Parameters:
handle - handle of the agent that publishes this information
name - name under which the value can be found
value - the value to be published
Throws:
AgentScapeException - If there is some problem in registering the (name, value) pair.
See Also:
lookupPublished

lookupPublished

public java.util.Map<AgentHandle,java.lang.String> lookupPublished(java.lang.String name)
                                                            throws AgentScapeException
Lookup a value that was previously published under a certain name with the method publish.

Parameters:
name - name under which the value was published
Returns:
Map containing the values and the handles of the agents that published them.
Throws:
AgentScapeException
See Also:
publish

lookupPublished

public static java.util.Map<AgentHandle,java.lang.String> lookupPublished(AgentScapeApi api,
                                                                          java.lang.String name)
                                                                   throws AgentScapeException
Throws:
AgentScapeException
See Also:
lookupPublished

getAgentCPUtime

public long getAgentCPUtime()

getContext

public org.mortbay.jetty.servlet.Context getContext()
Return context in which servlets of this agents are executed.

Returns:
context for servlets of this agent.

publishServlet

public void publishServlet(java.lang.String name,
                           javax.servlet.http.HttpServlet servlet)
Publish a servlet for this Agent. This servlet can be accessed on a browser via: http://lookupserver/agents/agenthandle/name

NOTE: servlets DO NOT migrate with agents! Servlets must be published again after a migration!

Special log servlet is always available for each agent. This servlet does not have to be published. The log is available for a *short while* after the agent has finished.

Parameters:
name - name of servlet
servlet - published servlet

getServletNames

public java.util.Set<java.lang.String> getServletNames()
Lists the servlet names this agent has published.

Returns:
list of published servlet names

getServlet

public javax.servlet.http.HttpServlet getServlet(java.lang.String name)
Get this agent's servlet by name.

Parameters:
name - name of the servlet
Returns:
servlet associated with this name


Copyright © 2003, 2004 IIDS Group. All Rights Reserved.