Subject: Using properties instead of command line arguments
From: Dick Cowan (rm.cowan@verizon.net)
Date: Fri Feb 21 2003 - 00:21:04 MET
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. We recognized this problem so we
created property handling classes which were subsequently provided
to JADE and have been part of the jade.util package for awhile now.
LEAP also makes use of properties in lieu of passing in arguments.
The classes I'd like you to consider are BasicProperties,
EnhancedProperties, and ExpandedProperties. Please see the java doc under
jade.util for extensive documentation on these classes. Briefly they are:
1. 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}.
2. EnhancedProperties - Provides a concrete implementation of
ImportableProperties
useable in the J2SE (desktop) world.
3. 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 3 files (between dashed lines). BasicAgent is intended to
provide basic
property support for all agents. You could extend this class rather
than jade.Agent for your custom agents. DemoAgent simply provides
an example of this. You can run this agent. Finally setup.properties
shows an example property file.
Please see additional comments in the source code below for usage and
more detailed explanation.
Enjoy,
Dick
PS - All this is open source so use as you like. I'll be happy to
answer simple questions as time permits.
----------------- 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 could now extent this class.
* @author <a href="mailto:rm.cowan@verizon.net">Dick Cowan</a>
*/
public class BasicAgent extends Agent {
public static String PROP_NAME = "setup.properties";
private BasicProperties properties = null;
private String[] presentedArgs = 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;
}
/**
* Called by Jade to set the agents arguments so we use it to
* initialize our properties. It calls getProperties to
* get the starting properties, copies them into a new instance
* of ExpandedProperties, calls its parseArgs method of handle
* the presented arguments, and then replaces our starting
* properties with this result. This ensures that empty setting
* in the arguments will overlay those in starting.
* arguments.
* @param args The arguments passed to the agent.
*/
public void setArguments(String[] args) {
presentedArgs = args;
ExpandedProperties newProperties = new ExpandedProperties();
newProperties.copyProperties(getProperties());
newProperties.parseArgs(args);
setProperties(newProperties);
}
/**
* Fetch the String[] which was given to setArguments.
* @return The value given to setArguments - may be null;
*/
public Object[] getArguments() {
return presentedArgs;
}
/**
* Jade calls this method on startup (after calling setArguments) so
we use it
* to initialize. If the agents properties contains "dump=true", the
properties
* will be displayed.
*/
protected void setup() {
if (getProperties().getBooleanProperty("dump", false)) {
// Since the journal is capturing System.out, this will be
captured
// and written to the journal with proper header.
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.
* @author <a href="mailto:rm.cowan@verizon.net">Dick Cowan</a>
*/
public class DemoAgent extends BasicAgent {
int infoLevel;
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(10000);
}
}
}
/** The <CODE>setup()</CODE> method is called by the agent container
as part
* of the the agent intialization after the agent's contructor is called.
* @see jade.core.Agent#setup()
*/
protected void setup() {
super.setup(); // To initialize our properties
MyBehaviour b = new MyBehaviour(this);
addBehaviour(b);
System.out.println("Agent "+getLocalName()+" is running.");
infoLevel = getProperties().getIntProperty("infoLevel", 2);
System.out.println("Info level=" + infoLevel);
}
}
----------------- Setup.properties ---------------------
# 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}
This archive was generated by hypermail 2a22 : Fri Feb 21 2003 - 00:18:20 MET