How to use arguments or properties to configure your agent.

Author: Dick Cowan, Menehune Software Inc.

Email: rm.cowan@verizon.net

Date: February 22, 2003. Revised: June 3, 2003

Java platform: J2SE

JADE version 2.5 and above.

JADE provides a simple mechanism to pass arguments to agents via the command-line or via the in-process interface.

For instance, the following command line passes 3 arguments to the agent FooAgent:

    java jade.Boot foo:FooAgent(1 arg2 "This is argument 3")

the three arguments can then be extracted by the FooAgent code via a simple call to the Agent method getArguments() that returns an array of type java.lang.Object.

    public void setup() {
        Object[] args = getArguments();
        String arg1 = args[0].toString(); // this returns the String "1"
        String arg2 = args[1].toString(); // this returns the String "arg2"
        String arg3 = args[2].toString(); // this returns the String "This is argument 3"
    }

The same arguments can be passed via the in-process interface as follows:

    Object args = new Object[3];
    args[0] = "1";
    args[1] = "arg2";
    args[3] = "This is argument 3";
    AgentController dummy = ac.createNewAgent("foo", "FooAgent", args);

Because of the usage of an array of Object rather than an array of String, the in-process interface can also pass complex arguments to an agent, such as the reference to another Java object. If you want a String argument, it is best to use the object argument's toString() method to fetch a string representation of the object rather than simply casting it as a String.

The command line can also be effectively used in order to pass general properties to all the agents in the system. For instance, the following command line sets to 3 the value of the property named verbosity:

    java jade.Boot -verbosity 3 foo:FooAgent(1 arg2 "This is argument 3")

The same property can be set also via the in-process interface, in particular by setting that value in the Profile object:

    Profile p = new ProfileImpl();
    p.setParameter("verbosity","3");
    AgentContainer ac = rt.createAgentContainer(p);

In both cases, all agents can then get that value via the getProperty method call provided by the jade.core.Agent class:

    String verbosity = getProperty("verbosity", "0");

However, attempting to pass other than a few simple arguments via the command line is difficult. Particularly trying to do so in a platform neutral manner. LEAP also makes use of properties in lieu of passing arguments directly to the agent.

While working with the Agents for Mobility group at HP Labs, we recognized the need to provide agents with a richer and more flexible method of passing arguments to our agents than could be done from the command line. The classes we created became part of the JADE 2.5 release.

The classes of interest are BasicProperties, EnhancedProperties, and ExpandedProperties. The preceding links should take you to the API documentation for these classes. Briefly they are:

  1. jade.util.BasicProperties - Provides the foundation class for property management. It is designed to be usable in the restrictive J2ME CLDC environment. It provides enhanced property management as well as providing support for values containing strings of the form ${key}.
    A property may be set such that it can't be altered by ending the key value with an exclamation point; e.g. agentClass!. One still references this property with its basic name without the exclamation point.
  2. jade.util.EnhancedProperties - Provides a concrete implementation of ImportableProperties useable in the J2SE (desktop) world.
  3. jade.util.ExpandedProperties - Extends EnhancedProperties and adds support for fetching system environment variables (those usable from the OS shell). This class would need to be carefully considered in other than Windows or Unix/Linux environments.
By using property files you can include all the arguments you wish. From the command line to initialize an agents properties from a file named "myprop.properties", you would use:
    java jade.Boot foo:DemoAgent(import:myprop.properties)
One property file may import from another, so inside myprop.properties you could include an import to another file. You can get at your environment variables using a key like ${CLASSPATH}. There are many convenient getter methods provided in BasicProperties.

Shown below are:

  1. BasicAgent.java - Intended to provide basic property support for all agents. You could extend this class rather than jade.Agent for your custom agents. Of particular interest in this class is the method getProperties() as it attempts to initialize the starting property collection by having the class loader load properties from a file called "setup.properties". This initial collection may then be altered by any properties supplied at run time. Loading the initial collection using the class loader is important as this permits you to place the property file in the same jar as your class files - simplifying installation and usage by others. This could be where you provide all the default values for infrequently modified things such as class names or GUI settings.
  2. DemoAgent.java - Provides a simple example agent which uses BasicAgent. You can run this agent.
  3. setup.properties - An example property file.

The two java files contain additional comments on implementation and usage.

Testing:

  1. Copy the text in each section below and save to a file whose name is the same as the header. Place these three files in the same directory.
  2. Change to the directory where you saved the files.
  3. Compile the two Java files.
  4. With jade.jar as well the current directory on your classpath run the demo with:
    java jade.Boot demo:DemoAgent
  5. DemoAgent simply displays its properties every N seconds, where N is specifed by the property "delay.seconds".

Optional testing:

  1. Modify some of the attributes provided by the setup.properties file at run time. As set in that file the delay time is 10 seconds. You could change it to 20 from the command line with:
    java jade.Boot demo:DemoAgent(delay.seconds:20)
    This will change the attribute at run time but not modify the value in the file.
  2. Create another property file, called test.properties and have its properties add to or overlay those in setup.properties with:
    java jade.Boot demo:DemoAgent(import:test.properties)
  3. Add an import statement to test.properties to import another property file. Use some system environment variable (e.g. ${JADE_HOME}) to set some property or locate the property file.

BasicAgent.java

import java.io.InputStream;
import java.io.IOException;

import jade.core.Agent;
import jade.util.BasicProperties;
import jade.util.ExpandedProperties;

/**
  * Example of a useful base class for handing agent arguments.
  * Classes which formerly extended jade.Agent may now extend this class.
  */
public class BasicAgent extends Agent {

     public static String PROP_NAME = "setup.properties";

     private BasicProperties properties = null;

     /**
      * Sets the agents properties.
      * @param aProperties The properties to be used.
      */
     public void setProperties(BasicProperties aProperties) {
         properties = aProperties;
     }

     /**
      * Returns the agents properties.
      * If called and the properties are null, we will attempt to initialize
      * them from a property file located as a resource by the same class
      * loader which loaded this class. If this class is in a package, we
      * look for the property file using the same package name. For example,
      * if this class were called myAgent and is in a package named
      * com.foo.bar then, it will attempt to load com/foo/bar/setup.properties.
      * If no package name or class not in jar, loader will look in the same
      * place as it found the class. If it isn't there thats OK.
      * This process enables you to easily have a default collection of
      * properties which you include in the same jar file. You can change
      * individual properties from the command line or import another property
      * file. However, it always first initializes from the one described 
      * above.
      * Examples:
      * 1. To import from a second file which will overlay the initial 
      *    properties:
      *    java jade.Boot foo:DemoAgent(import:x.properties)
      * 2. To simply change one property:
      *    java jade.Boot foo:DemoAgent(CalendarChoice:Custom)
      *
      * Note: Use the colon between property name and its value. Windows does
      * very strange things with an equal sign.
      */
     public BasicProperties getProperties() {
         if (properties == null) {
             properties = new ExpandedProperties();
             String defaultPropName = PROP_NAME;
             try {
                defaultPropName = this.getClass().getPackage().getName().replace('.','/') +
                                   "/" + defaultPropName;
             } catch (Exception any) {
                 // ignore - likely class not in package.
             }
             InputStream propertyStream = this.getClass().getClassLoader().
                                               getResourceAsStream(defaultPropName);
             if (propertyStream != null) {
                 try {
                     properties.load(propertyStream);
                 } catch (IOException ioe) {
                     System.err.println("Error reading:" + defaultPropName);
                     System.exit(-1);
                 }
             }
         }
         return properties;
     }

     /**
      * Jade calls this method on startup so we use it to initialize the
      * agents properties. First, it will call getArguments() to get
      * the arguments as an array of objects. Second, it creates a similar
      * size array of strings by calling toString() on each object.
      * Finally, it will call getProperties() to get the initial property set
      * and then add those provided as arguments. If the properties contain
      * "dump=true", the properties will be listed to standard out.
      */
     protected void setup() {
         Object[] args = getArguments();  // JADE's getArguments
         if (args != null) {
             int len = args.length;
             String sargs[] = new String[len];
             for (int i=0; i < len; i++) {
                 sargs[i] = args[i].toString();
             }
             ExpandedProperties newProperties = new ExpandedProperties();
             newProperties.copyProperties(getProperties());
             newProperties.parseArgs(sargs);
             setProperties(newProperties);
         }
         if (getProperties().getBooleanProperty("dump", false)) {
             System.out.println("----- " + getLocalName() + "'s properties:");
             getProperties().list(System.out);
             System.out.println("----- end of properties -----");
         }
     }
}

DemoAgent.java

import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;

/**
 * Example to show usage of BasicAgent.
 * All it currently does is display its properties every N seconds
 * where N is specified by the property "delay.seconds".
 */
public class DemoAgent extends BasicAgent {
    int delaySeconds;

    class MyBehaviour extends CyclicBehaviour {
        public MyBehaviour( Agent a ) {
            super(a);
        }

        public void action() {
            while (true) {
                System.out.println("----- " + getLocalName() + "'s properties:");
                getProperties().list(System.out);
                doWait(delaySeconds * 1000);
            }
        }
    }

    /**
     * This method is called by the agent container as part of the
     * agent intialization after the agent's contructor is called.
     */
    protected void setup() {
        super.setup();  // To initialize our properties
        MyBehaviour b = new MyBehaviour(this);
        addBehaviour(b);
        System.out.println("Agent "+getLocalName()+" is running.");
        delaySeconds = getProperties().getIntProperty("delay.seconds", 10);
        System.out.println("Delay seconds=" + delaySeconds);
    }
}

setup.properties

# Used by DemoAgent as its delay between displays
delay.seconds=10

# Optional. Uncomment to choose calendar; VIEW is default
# Choices are: View, Simple, Palm, all, any
calendarChoice=Palm

# Optional. Used when calendarChoice is Simple.
SimpleCalendar.input=c:/pa/config/cowand-simplecalendar.properties

# Optional. Used when calendarChoice is Palm.
# The following specifies the name of the datebook file.
# It should be modified to match your installation.
PalmCalendar.datebook=c:/palm/dick_c/datebook/datebook.dat
# If you want alarms set with event notices use the following.
# Units of time may be minutes, hours, or days.
PalmCalendar.datebook.alarm=15 minutes

# These are used by the weather service.

weather.state=HI
weather.city=HONOLULU
weather.zonecode=HIZ002

class.path=${CLASSPATH}


JADE is a trademark of CSELT.