In this brief "how-to", you will learn TuCSoN4JADE (t4j for short) main API available to JADE developers and how to use them in your code, for your JADE agents, as well as a bit of "behind the scenes" on how t4j works.
Assumptions are you are familiar with both JADE and TuCSoN.
Prior to reading this how-to is highly recommended to read the reference paper on integrating TuCSoN and JADE:
available from here
The first step in integrating TuCSoN and JADE has been implementing TuCSoN as a JADE service.
This means JADE BaseService
class has been extended with the TucsonService
class, representing TuCSoN service entry point. This class has to be used to get an helper class, extending JADE ServiceHelper
interface, working as the actual mediator between clients and the TuCSoN service: in t4j, the helper role is played by the TucsonHelper
interface---whose implementation class is hidden to clients. Its methods are quite self-explanatory if you know TuCSoN terminology, and are listed in the picture below.
The only "unusual" method is getBridgeToTucson()
: BridgeToTucson
is the class which TucsonHelper
delegates TuCSoN coordination operations invocation to.
BridgeToTucson
exposes the following API:
synchronousInvocation()
— lets clients synchronously invoke TuCSoN coordination operationsasynchronousInvocation()
— lets clients asynchronously invoke TuCSoN coordination operationsSynchronous Invocation. Given a coordination operation to perform (AbstractTucsonAction
subtypes, see t4j Javadoc), a maximum waiting time to be possibly suspended for (timeout
), and a reference to the caller Jade behaviour, the chosen coordination operation is requested to the active TuCSoN service synchronously w.r.t. the caller behaviour. This means the caller behaviour only is (possibly) suspended and automatically resumed by t4j as soon as the requested operation completes—returning the completion event reified by TucsonOpCompletionEvent
object.
Such mechanism encourages JADE programmers using t4j to adopt the same programming style suggested by the JADE Programmers Guide (available here) regarding message reception:
the communication method – synchronousInvocation()
in t4j, receive()
in JADE – is first called
the result is checked, and (i) handled, if available, (ii) otherwise method block()
is called
@Override
public void action () {
// field 'mt' stores the ACL message template
final ACLMessage msg = myAgent.receive(mt);
if (msg != null) { // message received: process it
...
} else { // message not received yet: wait
block();
}
}
@Override
public void action () {
// field 'tuple' stores the TuCSoN tuple template
final Rd op = new Rd(tcid, tuple);
final TucsonOpCompletionEvent
res = bridge.synchronousInvocation(op, Long.MAX_VALUE, this);
if (res != null) { // tuple found: process it
...
} else { // tuple not found yet: wait
block();
}
}
This allows JADE runtime – through the behaviours scheduler – to keep on scheduling others behaviours belonging to the caller agent while the invoking behaviour remains suspended (within JADE "waiting queue").
Asynchronous Invocation: "Interrupt Mode". Lets clients asynchronously invoke TuCSoN coordination operations, handling results "by interrupt".
In particular, when the requested operation completes, the JADE behaviour given as actual parameter is activated to handle the operation result-that is, put in the ready queue, ready to be scheduled.
The "result-handling" behaviour written by JADE programmers should implement t4j IAsynchCompletionBehaviour
interface: the setTucsonOpCompletionEvent()
method is the "hook" for t4j to share completion events between the caller and the "result handler" behaviour, transparently to JADE programmers.
Asynchronous Invocation: "Polling Mode". Lets clients asynchronously invoke TuCSoN coordination operations, handling results "by polling".
In particular, the caller agent gets a data structure (AsynchTucsonOpResult
, depicted below) representing the operation result, which it may query to check completion and (eventually) retrieve the actual result.
In both cases, regardless of whether the coordination operation suspends or not, the agent does not, thus the caller behaviour keeps on executing.
As a last note, the type hierarchy representing TuCSoN coordination operations is in package it.unibo.tucson.sd.jade.operations
as depicted in figure below.
NB: What follows is based on the "Book Trading" example scenario shipped within t4j distribution (see t4j "Getting Started", here).
If you want to work with t4j, remember to instruct the JADE platform to boot the TuCSoN service, as explained in t4j "Getting Started", here.
Regardless of how you are willing to exploit TuCSoN services, you need to:
get the service helper class from TuCSoN service instance
ITucsonHelper helper = (TucsonHelper) this.getHelper(TucsonService.NAME);
[OPTIONAL] [1] start the TuCSoN node you wish to operate on
if (!this.helper.isActive(20504)) {
this.helper.startTucsonNode(20504);
}
get an ACC (which is actually associated to the BridgeToTucson
object you'll get from the helper in step 4)
this.helper.acquireACC(this);
get the bridge object through which all your TuCSoN operations will go
BridgeToTucson bridge = this.helper.getBridgeToTucson(this);
[OPTIONAL] [1] stop the TuCSoN node when its services are no longer needed
if (this.helper.isActive(20504)) {
this.helper.stopTucsonNode(20504);
}
Now, what to do next obviously depends on what your program logic needs. Anyway, you will likely perform some of the following operations:
build the identifier of the tuple centre you wish to use (e.g., putting "hello" tule on default TuCSoN node)
TucsonTupleCentreId tcid = this.helper.buildTucsonTupleCentreId(
"default", "localhost", 20504);
build the tuples you need (using usual TuCSoN facilities)
LogicTuple adv = LogicTuple.parse(
"advertise(provider("
+ this.getAID().getName()
+ "), service('book-trading')))");
build an "action", representing TuCSoN (meta-)coordination operations,
choosing from all the type hierarchy rooted in it.unibo.sd.jade.operations.AbstractTucsonAction
Out out = new Out(this.tcid, this.adv);
perform the action according to your preferred invocation semantics (e.g. asynchronous, "polling" mode)
AsynchTucsonOpResult res = this.bridge.asynchronousInvocation(out);
(e.g. asynchronous, "interrupt" mode)
this.bridge.asynchronousInvocation(out,
new AdvertisingCompletedBehaviour(this.adv), this);
private class AdvertisingCompletedBehaviour extends OneShotBehaviour
implements IAsynchCompletionBehaviour {...}
(e.g. synchronous mode)
TucsonOpCompletionEvent result =
BookSellerAgent.this.bridge.synchronousInvocation(in, null, this);
remembering, if needed, to exploit JADE's usual programming pattern
if (result != null) { // tuple found: process it
...
} else { // tuple not found: wait
block();
}
Author of this "how-to":
Authors of the add-on:
[1] You can also start/stop a TuCSoN node separately, from another Java class, bash script, or even by hand. See TuCSoN "Getting Started" available here for more info.