A quick walk through the MICA API

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.

unsw.cse.mica.data.Mob

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).

Transience

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.

Reserved slot names

The following slot names are reserved and are used by the system: creator, creationTime, deleter, deletionTime and persistence. Setting these slot names can lead to unexpected events and should be avoided.

unsw.cse.mica.agent.AgentTransport

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 getTypeManager() command.

  • 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 sharedPadLines 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.

unsw.cse.mica.agent.Agent

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.

Setting up Agents and Agent Transports

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.