There are several important classes that make up the MICA implementation; in this section, we will go through the most important classes and their methods.
The Mob is the basic unit of information storage and
communication in MICA. As previously mentioned, each Mob has a name, a
type and a set of slots that define it. Let's have a look at two real
Mobs (as output by its toString()
method).
Mob sharedPadLine_103 of type sharedPadLine has slots: creationTime: [2003-08-07 12:13:21.246] creator: [sharedPad_1] oldX: [69] oldY: [151] newX: [68] newY: [151]
Figure 4.1. A simple mob
In the above code, the mob's name is
sharedPadLine_103
(a name that was allocated
when this object was written to the blackboard) and its type is
sharedPadLine
. It has six slots, but all of the
slots have a single value. Let's look at a more complex
example.
Mob emailListReply_12 of type emailListReply has slots: creationTime: [2003-07-31 16:01:02.24] creator: [emailAgent] from: [waleed@cse.unsw.edu.au, foo@bar.com, bar@baz.com] subject: [What's up?, Bugs in MICA, Romeo and Juliet screening] count: [3]
Figure 4.2. A more complex Mob
Figure 4.2 shows slots containing multiple values. The current implementation allows only Strings to be stored in slots, but this is still a very flexible representation. For example, references to other mobs and complex data structures can be constructed using slots that contain references to other Mobs. Similarly, binary data can be stored using base-64 encoding.
The methods for mobs are consequently related to constructing a Mob. Basically, there are several families of methods. The complete documentation can be found in the java documentation.
Constructors: The typical constructor
used to make a Mob is the Mob(String
mobType)
method. This creates a new Mob of the
specified type, but with an undefined name and no slots.
Typically, the Mob has no name until a name is actually given to
the Mob by writing it on the blackboard.
Setting up slots: There are a number of
functions to set up slots. setSlot(String slotName,
List slotValues)
allows you to set up a slot with all
of its values, while addSlot(String slotName, String
slotValue)
allows you to add a new value to a slot.
addEmptySlot(String slotName)
allows you
to set up a slot that has no values in it.
Getting values from slots: There are
two primary methods for getting values from slots:
getSlot(String slotName)
gets all the
list of values for a slot, but since there is a very common case
where the list contain a single value, there is also the
getSlot1(Strong slotName)
which returns a
single String, rather than an entire list. To get a slot value as
an integer, use getSlot1AsInt(String
slotName)
.
On occassion, you want to use MICA merely as a traditional
publish/subscribe mechanism, i.e. you do not want to save the mob
you are writing on the blackboard, you just want that mov delivered
to anyone who is interested. Such mobs can be labelled as transient.
Transient mobs are not stored on the blackboard, but other agents
interested in the mobs are notified. To mark a mob as transient, use
the makeTransient()
method.
Note that as of Mica 2.0, transience can also be defined using the type manager. If a type is specified in this way, the blackboard will ensure that all Mobs of that type are transient, so agents creating these mobs are not required to do so.
AgentTransport
is an interface that
represents a connection to the blackboard. As such, the
AgentTransport
is the only "view" that the
agent actually gets of the blackboard. For this reason, the
AgentTransport
encapsulates all the
functionality of the board. Whenever an agent wants to communicate
with the blackboard it does so through the agent transport. Similarly,
whenever the agent transport receives information about a new mob,
this is passed from the agent transport to the agent.
Because the AgentTransport
is a proxy for
the blackboard, all its methods are basically proxy commands that are
forwarded to the blackboard. These are:
Connection commands:
connect(String agentName)
and
disconnect()
are used to connect to the
blackboard. connect()
returns the agent
name that was given to the agent. The agent can request a
particular name, but this may not be granted since another agent
with this name may already exist.
disconnect()
obviously disconnects from
the blackboard.
Getting type information from the
blackboard: Agents can access the blackboard's type
manager using the
command.getTypeManager()
Registering and unregistering:
Registering is the way that you let the blackboard know that you
are interested in objects of a particular type. For instance, if
an agent is interested in lines, it registers for
sharedPadLine
mobs. Whenever a
sharedPadLine
mob is written to the
blackboard, the agent is sent a copy of the new mob. To register,
the register(String mobType)
can be used.
Similarly, if an agent is no longer interested in
sharedPadLine
s anymore, it unregisters with
unregister(String mobType)
Writing things on the blackboard: To
write on the blackboard, writeMob(Mob m)
can be used. writeMob
returns the name
that the object is finally given. The blackboard then handles the
forwarding of this message to anyone who is interested -- the
agent need not concern itself with how the information is
distributed.
Deleting mobs from the blackboard:
deleteMob(String mobName)
can be used to
delete information from the blackboard. However, this should be
done very carefully, since other mobs may refer to the mob.
Getting mob information from the
blackboard: To retrieve information from the
blackboard, one can use readMob(String
mobName)
if the name of the mob is known or
mobSearch(String micaQuery)
if a mob with
particular properties is sought. For a description of the query
language, see the section called “The MICA query language”.
mobSearch
will return all mobs that have
the desired properties.
Mica V2 provides two primary implementations of the
AgentTransport interface:
LocalAgentTranport provides a direct programmatic connection between the agent's transport and the blackboard transport. Note that this implementation has not been thoroughly tested.
CompoundTransport
combines a
connection type (AgentConnection
) with a
protocol (AgentProtocol
) to create a
versatile component-based transport system. Currently available
connection types are LocalAgentConnection
and TCPAgentConnection
, while the only
protocol currently implemented is
XMLAgentProtocol
.
XMLOverTCPAgentTransport
sends
snippets of XML over a TCP network connection. This is the most
frequently used transport method, so much so that a new class has
been created to simplify the process of creating this transport
type. Currently this is the only type of transport used by
MicaRunner.
Agent
encapsulates a single autonomous
unit for doing computation on the blackboard. It is implemented as an
interface. Implementing an agent consists of writing seven methods;
and DefaultAgent
provides a reasonable default
for most of those.
setAgentTransport(AgentTransport
at)
and getAgentTransport()
are used so that the agent can redirect calls to the blackboard
through the appropriate agent. DefaultAgent
provides a default for these two methods. In general,
DefaultAgent
should be extended, but in
some cases it is more convenient to implement
Agent
so that the agent itself can
inherit from another class.
init(MicaProperties)
: This method
is called to start the agent operating. It is actually called by
the AgentTransport
(see the section below).
Note that the init()
method should return
quickly; in particular, the agent transport should not start
sending messages until init()
returns. If
some complicated execution takes place, it should be done in
another thread. Also note that the init()
method takes a MicaProperties object; these are usually extracted
from the startup file; but it provides a generic mechanism for
passing configuration info to the agent.
terminate()
: This method is called
to stop the agent operating. It is typically called by the
MicaRunner.
handleNewMob(Mob m)
This method is
called whenever a Mob we are registered for arrives.
handleDeletedMob(Mob m)
This method
is called whenever a Mob we are registered for is deleted. The mob
being deleted is included. This is useful, as this gives us a last
opportunity to make a local copy of the Mob. If you inherit from
DefaultAgent
, there is a default
implementation that does nothing.
handleTypeManagerChanged()
this
method is called whenever the blackboard's type manager changes.
The defaul is to do nothing.
That's it! At its core, to implement most agents requires
writing the the init
and
handleNewMob
methods.
DefaultAgent2
provides additional
functionaliy over DefaultAgent
, including
transport connection and disconnection, and providing a type manager
that is kept up-to-date with the blackboard's type manager.
GUIAgent
extends this further to provide
skeleton support for an agent needing a GUI. It ensures that
terminating the agent closes the GUI and vice-versa.
The following section discusses how agents and agents are set
up. However, if you use the MicaRunner
tool,
you need not concern yourself with such details; it handles the
setting up of agents and agent transports. On first reading, this
section can be glossed over.
Because the Agent
and the
AgentTransport
have a close relationship and
each can call the other, there are a few special hoops that have to be
jumped through in order to get them to work together. This is because
each need to know about the other, so it's tricky to set this up with
constructors and the like. The steps involved are:
Construct the Agent
.
Construct the AgentTransport
, but
ensure one of the parameters is the the Agent constructed in the
previous step.
In the constructor of AgentTransport
call the method Agent.setTransport(AgentTransport
at)
. This lets the agent know what its transport
is.
When the agent is ready to go, call the method
Agent.init()
This is typically the point
in the code when the agent will connect to the blackboard using,
say, an AgentTransport.connect()
call.