Making your agent do stuff: Agent Behaviours.

The previous example doesn't actually do anything, all code is just run inside the setup() method. Typical agents implement cmplex behaviours, which may involve multiple simultaneous related or unrelated tasks, rather than forcing you to write multithreaded agents (with all of the problems that this can cause) jade introduces a system of Behaviours to assist you in building and re-using agent functionality.

Essentially when using Jade's behaviours each agent can be seen as a set of cooperatively multithreading processes ,that is to say that each process gets run, and performs a portion of its task before actively yeilding controll back to the process scheduler. While this may seem old-fashioned it adds a degree of determinism to writing agents, and allows for a fairly natural decomposition of the agents overall behaviour.

Simple Behaviours:SimpleBehaviour

Let us return to the previous example, instead of printing out the information in the setup() method let us place it into the simplest type of behaviour: a SimpleBehaviour

Showing you cm30174/jade/examples/behaviours/HelloWorldBehaviors.java
package owen.agent.tutorials;

import jade.core.*;
import jade.core.behaviours.SimpleBehaviour;


public class HelloWorldBehaviours extends Agent{
        
        public void setup(){
                
                SimpleBehaviour hello_behaviour = new SimpleBehaviour(this){
                        
                        boolean finished = false;
                        
                        public void action(){
                                System.out.println("Hello World Behaviour run: Hello World!");
                                
                                System.out.println("-----About Me:-----");
                                System.out.println("My local name is:"+getLocalName());
                                System.out.println("My globally unique name is:"+getName() );
                                
                                
                                System.out.println("-----About Here:-----");
                                Location l = here();
                                
                                System.out.println("I am running in a location called:"+l.getName());
                                System.out.println("Which is identified uniquely as:"+l.getID());
                                System.out.println("And is contactable at:"+l.getAddress());
                                System.out.println("Using the protocol:"+l.getProtocol());
                                
                                finished = true;
                        }
                        
                        public boolean done(){
                                return finished;
                        }
                };
                
                
                addBehaviour(hello_behaviour);
                
                
                
        }
}
Note:

Note the use of anonymous classes, as with Swing, we tend to prefer creating classes which handle callbacks on the fly for the majority of simple bebehaviours. See the Java tutorial section for a bit more information or look on the web.

In the above example, the semantics are identical to the previous example, however we have created an object using an anonymous class, based on SimpleBehaviour and filled its action() and done() methods.

The action() in any SimpleBehaviour (or a descendant) is what actually does the work. Because each behaviour is only expected to do a small aount of work in one go, the action() method should not spend any great amount of time doing anything (as this blocks other behaviours which may be important), this applies especially to things like waiting for messages. Leaving that aside, you can implement a long-runnning behaviour in several chunks using simple behaviour by making the action method re-entrant. That is to say when action is called, you do a small amount of work and save some state about where you are , then return from action, eventually your behaviour will be scheduled again whence you should pick up where you left of and continue. done() gets called every time your behaviour is scheduled, when it returns true, the scheudler stops sheduling your agent and removes it from its parent.A simple example of a reentrant behaviour is as follows:

Showing you cm30174/jade/examples/behaviours/DecativeReEntrant.java
package owen.agent.tutorials;

import jade.core.*;
import jade.core.behaviours.SimpleBehaviour;



public class DecativeReEntrant extends Agent{
        public void setup(){
                SimpleBehaviour decative = new SimpleBehaviour(this){
                        
                        boolean finished = false;
                        int state = 0; 
                        
                        public void action(){
                                switch(state){
                                        case 0:
                                        System.out.println("Do");
                                        break;
                                        case 1:
                                        System.out.println("Re");
                                        break;
                                        case 2:
                                        System.out.println("Me");
                                        break;
                                        case 3:
                                        System.out.println("Fa");
                                        break;
                                        case 4:
                                        System.out.println("So");
                                        break;
                                        case 5:
                                        System.out.println("La");
                                        break;
                                        case 6:
                                        System.out.println("Wo");
                                        break;
                                        case 7:
                                        System.out.println("Bo");
                                        break;
                                        case 8:
                                        System.out.println("Ti");
                                        break;
                                        case 9:
                                        System.out.println("Do");
                                        finished = true;
                                        break;
                                        
                                }
                                state++;
                        }
                        
                        public boolean done(){
                                return finished;
                        }
                };
                
                
                addBehaviour(decative);
                
                
        }
}

Note:

Note that there is a simple behaviour called OneShotBehaviour which is designed for behaviours which only need a single execution of action() to complete, i.e. it sets the done() return value automatically on your behalf.

Composite Behaviours: Complicating things

Behaviours can be nested within other behaviours to form Composite Behaviours. Typically applications of this are sequences of behaviours, parallel behaviours and cyclic behaviours.

A sequential behaviour can be created to perform the above task as follows:

Showing you cm30174/jade/examples/behaviours/DecativeSequential.java
package owen.agent.tutorials;

import jade.core.*;
import jade.core.behaviours.SequentialBehaviour;
import jade.core.behaviours.OneShotBehaviour;


public class DecativeSequential extends Agent{
        public void setup(){
                
                SequentialBehaviour s1 = new SequentialBehaviour(this);
                
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Do");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Re");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Me");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Fa");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("So");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("La");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Wo");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Bo");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Ti");}});
                s.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("Do");}});
                
                addBehaviour(s);
                
        }
}

Here we create a sequential behaviour, then add 10 simple sub-behaviours to perform the same task.

Likewise we can use ParallelBehaviour to execute several tasks in parallel thus:

Showing you cm30174/jade/examples/behaviours/ParallelBehaviourAgent.java
package owen.agent.tutorials;

import jade.core.*;
import jade.core.behaviours.SequentialBehaviour;
import jade.core.behaviours.ParallelBehaviour;
import jade.core.behaviours.OneShotBehaviour;


public class ParallelBehaviourAgent extends Agent{
        public void setup(){
                
                SequentialBehaviour s1 = new SequentialBehaviour(this);
                
                s1.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("1) This ");}});
                s1.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("1) is");}});
                s1.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("1) the ");}});
                s1.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("1) first");}});
                s1.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("1) behaviour");}});
                SequentialBehaviour s2 = new SequentialBehaviour(this);
                
                s2.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("2) This ");}});
                s2.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("2) is");}});
                s2.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("2) the ");}});
                s2.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("2) second");}});
                s2.addSubBehaviour(new OneShotBehaviour(this){public void action(){System.out.println("2) behaviour");}});
                
                ParallelBehaviour p = new ParallelBehaviour(this,ParallelBehaviour.WHEN_ALL);
                
                p.addSubBehaviour(s1);
                p.addSubBehaviour(s2);
                
                
                addBehaviour(p);
                
        }
}

When executed this will interleave the execution of the two seqential sub-behaviours until both are yeilding something like:

1) This
2) This
1) is
2) is
1) the
2) the
1) first
2) second
1) behaviour
2) behaviour

(The Specification of ParallelBehaviour.WHEN_ALL in the constructor indicates to wait for all sub-behaviours to finish, use ParallelBehaviour.WHEN_ANY if you want to finish the parallel behaviour when any of the children have finished.

Note:

Each agent has an internal parallel behaviour which we are accessing with addBehaviour if you add multiple behaviours to the agent with this call they will be executed in parallel in the same way. Also note that behaviours are scheduled deterministically, in a round-robin fashion, in the order they were added. You should also note that behaviours can be added to agents and composite behaviours while they are running, in a generative way.

You can also create Cyclic behaviours using the CyclicBehaviour class, which executes a single (possibly composite) behaviour over and over again (this is just like a SimpleBehaviour that never returns false from done()

FSMBehaviour: The mother of composite behaviours

There is a final composite beviour called FSMBehaviour which allows you to build arbitrarily complex finite state machines based upon behaviours this is useful for interaction protocols, and is the basis for the more complex interation behaviours like Conract net. It is not covered here.

Off the shelf Complex behaviours

Jade provides a number of off-the shelf behaviours for implementing FIPA interraction protocols in the packages including

In the above cases the protocols behaviour classes must either be extended in order to override handler methods (as with handleResponse(...) in SimpleAcheveREResponderer) or you must register handler behvaviours to deal with protocol events (i.e. registerPrepareResponse in ContractNetResponder .

Summary

Behaviours can be used as the building blocks of your agents and can be used for things like simple communication and instanting complex multi-party interaction protocols.