Tutorial: how to start developping MadKit agents in Java

This section introduces various examples that one can use to get into MadKit and learn how to build his or her own agents in Java. See {{section}} the sections on scripting languages to learn how to build agents using other languages.

Creating a new plugin

The MadKit structure is based on plugins. Each plugin must be considered as a module which contains a set of agents. A plugin is seen in MadKit as a directory

A first agent "Hello world" agent

In this section, you will learn how to create a simple "Hello World" agent in Java. This agent does nearly nothing: its main behavior consists simply in printing 10 times a message of "happiness":

import madkit.kernel.*;

public class HelloWorldAgent extends Agent{

  public void activate(){
    println("Java Hello World Agent");
  }
         
  public void live(){
    int n = 10;
    while (n > 0){
        println("I am OK : "+n);
        pause(1000);
        n = n-1;
    }
  }

  public void end(){
    println("I am dead, arghhh");
  }
}

Note: it is important to declare the agent class as public.

Compiling the source files

To get a working agent from this definition, copy it into a file named HelloWorld.java, compile it, with the following command where %MADKIT_DIR% (in a Winxx configuration) or $MADKIT_DIR (in a Unix configuration) represents the location of the MadKit directory:

javac -classpath %MADKIT_DIRECTORY%\libs\madkit\madkit.jar *.java		(Win)	
javac -classpath $MADKIT_DIRECTORY/libs/madkit/madkit.jar *.java			(Unix)

Then build a jar and copy this jar into the autoload directory of MadKit:

jar cf helloworld.jar *.class
copy helloworld.jar %MADKIT_DIRECTORY%/autoload			(Win)	
jar cf helloworld.jar *.class
copy helloworld.jar $MADKIT_DIRECTORY/autoload				(Unix)

Instead of typing your command directly, you may prefer to use the Ant building tool. Ant is a Java based make tool developed by the Apache Jakarta project which has become a de facto standard within the Java community for building applications. In the helloworld directory, we have added a build.xml file which contains all the necessary information to build an agent from a set of java files. Install the Ant tool, and type ‘ant’ within the helloworld directory. That’s all...

You may use the provided build.xml file as a template for your own project. Just change the madkit.dir property and the jarname property to suit your project.

Running the HelloWorldAgent

Restart MadKit, double click on the tree on the helloworld.jar representing the autoload directory to see all agents of the jar, double click on the HelloWorldAgent, and you will get the following snapshot:

Figure 3.1. a simple HelloWorld agent

A first simple organizational agent: remote counting

This example introduces two new concepts: the use of groups and roles to index agents, and the definition of graphic interfaces

The counter agent

This example introduces a simple agent that starts counting when it receives a "start" message and stop counting when it receives a "stop" message. Here is its definition in Java:

import madkit.kernel.*;
import makdit.libs.messages.StringMessage;

public class CounterAgent extends Agent{

	boolean counting = false;
	
	public void activate(){
		println("I am a counter");
		createGroup(true,"demo.counter",null,null);
		requestRole("demo.counter","counter",null);
	}
    
	public void live(){
	    int n = 0;
	    Message m;
	    while (true) {
	    	if (!counting){
	    		println("I am stopped and wait for a start message");
	    		m = waitNextMessage();
	    		handleMessage(m);
	    	} else {
	    		println("counting: " + n++);
	    		pause(1000);
	    		m = nextMessage();
	    		handleMessage(m);
	    	}
	    }
	}
	
	void handleMessage(Message m){
		if (m instanceof StringMessage){
			String s = ((StringMessage)m).getString();
			if (s.equals("start"))
				counting=true;
			else if (s.equals("stop"))
				counting=false;
		}
	}
}

The definition is quite simple: the activate() method creates a group called demo.counter and the agent requests to play the role counter in this group.

Note: the first parameter of the createGroup primitive has the value true. This means that the demo.counter group is distributed over the network. Thus, if you connect other kernels (see {{section}} to learn how to connect distant kernels), this group, and all agents and role within, will be seen by these other kernels.

The live method is responsible for the main behaviour of the agent. When the agent does not count (variable counting==false), it simply waits for new messages. When it receives a "start" message, it starts counting. The pause(1000) statement is used to let the agent "pause" a second between two increments. The handleMessage method processes incoming messages and sets the counting variable accordingly.

To compile and run this agent use the procedure presented with the "HelloWorld" agent and replace helloworld.jar by counter.jar.

When launched, the counter agent does not count. To make it count, it is necessary to use another agent to send it StringMessages. A simple way to do it consists in using the Editor agent which is able to send StringMessages to all agents playing a specific role in a specific group. To make it go into the demo.counter group and sends StringMessages, see {{reference in the doc}}. In this example, through the GUI panel of the EditorAgent choose the group demo.counter, add a new role eded(note: the name of the role is not important in this example); then select the target group and role: select demo.counter as the group target and counteras the role target. Now, all messages from the editor will be sent to all agents playing the role counter in the group demo.counter.

Figure 3.2. A Counter agent controlled by a simple Editor agent

Building its own GUI interface: controlling the counter agent

It is also possible to create an agent to control the behavior of the counter agent. The following code describes an agent, called CounterControllerAgent which displays a graphic interface to start and stop a CounterAgent.

import madkit.kernel.*;
import madkit.lib.messages.StringMessage;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

/**
* A simple demo agent which controls the counterAgent, sending
* a "stop" or a "start" message on request
* @author J. Ferber
* @date 05/2002
*/

class CounterControllerGUI extends JPanel implements ActionListener {
	CounterControllerAgent ag;
	
	CounterControllerGUI(CounterControllerAgent _ag){
		ag = _ag;
		JButton bStart=new JButton("start");
		JButton bStop=new JButton("stop");
		add(bStart);
		add(bStop);
		bStart.addActionListener(this);
		bStop.addActionListener(this);
	}
	
	public void actionPerformed(ActionEvent e){
		String s = e.getActionCommand();
		if (s.equals("start"))
			ag.sendStart();
		else if (s.equals("stop"))
			ag.sendStop();
	}
}

public class CounterControllerAgent extends Agent{

	boolean counting = false;
	CounterControllerGUI gui;
	
	public void initGUI(){
		gui = new CounterControllerGUI(this);
		setGUIObject(gui);
	}
	
	public void activate(){
		createGroup(true,"demo.counter",null,null);
		requestRole("demo.counter","controller",null);
	}
    
	public void live(){
	    while (true){
			Message m = waitNextMessage();
		}
	}
	
	void sendStart(){
	  this.broadcastMessage("demo.counter","counter",new StringMessage("start"));
	}
	
	void sendStop(){
	  this.broadcastMessage("demo.counter","counter",new StringMessage("stop"));
	}
}

The class CounterControllerAgent describes a Swing component which contains the two buttons start and stop that are used to remote control the CounterAgent.

The class CounterControllerAgent describes a simple agent whose behavior consists in broadcasting a StringMessage to all agents playing the role counter in the group demo.counter. Note that the broadcastMessage primitive is used instead of sendMessage. It is also interesting to note that you may run a CounterAgent on one kernel and a CounterControllerAgent on another kernel and make them work together, providing that the two kernels are connected, without changing a line of code!

The following figure shows an example of a counter agent controlled by a CounterControllerAgent

Figure 3.3. A Counter agent controlled by a simple Editor agent