|
|
Janet.CAS |
|
|
|
Janet.ADÉ |
|
|
|
Defining
a Command-Interpreter Pair
Commands
are in general simple to define
as they only contain a notification and carry input/output data. Figure
7 shows a sample command definition: a command has to be made
serializable and needs to have a unique name. Attributes can be added
as required by the user.
|
|
package myApp;
import java.io.Serializable;
import org.almendra.janet.cas.scheduling.ICommand;
public class
MyCommand implements ICommand, Serializable
{
public static final String QualifiedName = "myApp.MyCommand";
protected List
params = new ArrayList();
public
MyCommand(List
params)
{
super();
this.params
=
params;
}
public String getQualifiedName()
{
return QualifiedName;
}
public List
getParams()
{
return params;
}
//
other required methods of
interface ICommand
omitted for brevity
} |
|
Figure 7: Sample command definition |
|
Interpreters
are
more
interesting
than
commands
since
they contain executable code. Figure 8 shows a sample
interpreter definition: an interpreter needs to define an execute(...) method, which is
invoked by the agent's scheduler when the associated command is
processed. This method is the interpreter's entry
point where execution of the interpreter starts. Furthermore, an
interpreter needs to specify all commands in response of which it needs
to be invoked by implementing the commandNames()
method. The agent's scheduler executes the first matching interpreter
it finds. |
|
package myApp;
import org.almendra.janet.cas.scheduling.CommandAccessor;
import org.almendra.janet.cas.scheduling.IInterpreter;
import
org.almendra.commons.util.exception.InvalidMessageException;
import org.almendra.commons.util.collection.StringList;
public class MyInterpreter implements IInterpreter
{
public MyInterpreter()
{
super();
}
public void execute(CommandAccessor cmdAccessor)
{
if
(cmdAccessor.getCommand() instanceof MyCommand)
{
MyCommand command = (MyCommand) cmdAccessor.getCommand();
List params = command.getParams();
doSomething(params);
}
}
public StringList commandNames()
{
return new
StringList(MyCommand.QualifiedName);
}
}
|
|
Figure 8: Sample interpreter definition |
|
When an interpreter is invoked by an
agent's scheduler the so-called CommandAccessor
is passed on to the interpreter as a parameter to the execute(...) method. The CommandAccessor provides access to the command executed
by the interpreter and to the agent's application, the node's object
spaces and event registries and to all other agents in the cluster
through proxies. A system agent is granted access to internal objects
of the node in addition. An agent of a user defined application is not
granted such access to protect the node's internal state from being
corrupted from applications outside its core. Calling a method that
returns a node's internal objects results in an InsufficientPrivilegeException to
be thrown if not called by a system agent. |
|
Sending a
Command |
|
Only an agent can send a command to
another agent. Since the executable part of an agent is comprised of
the interpreters of its capability it is only possible to send a
command to another agent from within the execute(...)
method of an
interpreter. |
|
public class
MyInterpreter implements IInterpreter
{
// …
public void
execute(CommandAccessor cmdAccessor)
{
if(cmdAccessor.getCommand() instanceof MyCommand)
{
ICommand
myCommand = new MyCommand();
IAgentProxy agent
=
cmdAccessor.getAgent(“nodeName”);
agent.accept(myCommand);
}
}
// …
} |
|
Figure 9: Sample interpreter that sends a
command to an agent of the same name
as itself pertaining to the same
application and residing on node
<nodeName>
|
|
As shown in figure 9 the interpreter
retrieves a proxy to the destination agent from the CommandAccessor and
sends a command to it. The proxy takes care of passing the command to
the destination agent and hides the complexity to accomplish this task
from the user. Figure 9 shows a very simple case where the
destination agent has the same name as the sending agent and resides on
a node named <nodeName>. There is no way to obtain a proxy to an
agent belonging to a different application than the sending agent. |
|
// …
if(cmdAccessor.getCommand() instanceof
MyCommand)
{
AgentPath
agentPath = new AgentPath(“nodeName”, “myCapability”,
“myAgentName”);
IAgentProxy agent
=
cmdAccessor.getAgent(agentPath);
ICommand
myCommand = new MyCommand();
agent.accept(myCommand);
}
// … |
|
Figure 10: Sending a command from within
an interpreter
to an agent specifying an AgentPath. |
|
In figure 10 a more
"sophisticated" example is shown where the complete path to the
destination agent is specified to obtain a proxy to it. If the agent
specified by the path does not exist, a NoSuchAgentException is thrown.
Thrown exceptions were omitted in the samples for brevity. It is also
possible to define a callback handler that is invoked when an expected
answer has arrived from the destination agent. The interested reader is
referred to the more detailed documentation
for an explanation. |
|
Ontologies and ACLs
For the time being Janet does not support
an explicit ontology or ACL. Ontologies and ACLs still seem to be in a
state of ongoing research and development. It therefore appears not
appropriate to make a choice in favor of a specific ontology or ACL at
the time of writing. This is contrary to research-oriented agent
systems where using ontologies and ACLs is part of the research work.
The approach in Janet is to wait and see how ontologies and ACLs will
develop in the future. Since the idea of Janet is to bring multi-agents
systems to business applications and industrial applications an
eventual future choice for an ontology will probably be made in the
direction of BPEL (Business
Process Execution Language) and/or semantic Web services using OWL. However, since a
user of Janet has full control of her application, she can plug in
whatever ontology and ACL she wants to use.
|
|
|