
The FAQ provides general information about developing using the ADK software. It also includes the latest troubleshooting tips on ADK development.
Typical tasks and applications of mobile agents include remote systems monitoring and management, distributed application integration (with agents wrapping the various applications or data sources), workflow automation, dynamic deployment of (native) code and components, and more.
Yes
and No. Let's start with "No".
A habitat is based on cooperative multitasking. All agents receive their
events -- heartbeats and messages -- within a limited number of threads.
It's impossible to change that without hacking the Java virtual machine.
You would not want to permanently assign every agent its own thread; this
would severely limit the number of agents that a habitat can run. Therefore,
it's important that agents do not use up a lot of time during their heartbeats.
A heartbeat is simply a slice of time, and an agent will have to relinquish
control of itself. If an agent starts abusing its timeslice, performance
of other agents will suffer.
Please note that from this point of view, a message is identical to a
heartbeat; any message will give an agent the chance to perform an action.
Misbehaving agents may not receive heartbeats, and in addition, their
messages mayl also be held. The exact definition of "too long"
and "abuse" is relative. If there is only one agent in a habitat,
the agent can spend more time on itself.
However, there are legitimate reasons for an agent
to perform a lengthy process. So there's a "Yes" answer. In
these cases, the agent CAN request a thread all of its own. It is important
to stress that not all agents should do this, otherwise the Java virtual
machine would run out of threads. Agents should also relinquish their
thread as soon as possible. It's very easy to start something in its own
thread by using the ExecutionEnvironment.scheduleRoutine(Routine
target) function. A Routine is a special Runnable that will be
executed by the habitat as soon as a thread becomes available. When the
Routine is done, the thread becomes available for other agents again.
More information on this topic can be found under the
Performance section.
Agents use String-based messaging to communicate with each other; this is done both for security reasons and compatibility reasons. The AFC provides several components to make this easier, based on FIPA standards. Agents can find each other using a Naming Service that, in turn, uses the JNDI (javax.naming) interface.
Send
a message through a conversation and set the task which is waiting for
a reply, as a message handler for this conversation. Then, you will only
receive messages that are replies to your original message. Here is a
coding example:
class
MyTask extends DefaultTask implements MessageHandler {
private Conversation myConversation;
protected void taskStarted() {
// Create conversation
myConversation = getAgentContext().createConversation(this);
// Create message
OutgoingMessage message = new Query(...);
// Send message
try {
myConversation.send(message);
}
catch (NoSuchAgentException nsae) {
fail("Unable to send message");
}
}
public void handleMessage(IncomingMessage message) {
// This message is a reply to our query....
}
}
By default the ADK uses a HTTP based protocol to transfer messages between habitats. Thanks to a plugin messenger architecture and messaging gateway tasks, alternative protocols such as SOAP and JMS are or can become supported.
In the ADK, "guaranteed delivery" refers to the following: after
sending a message, the sender will always be notified if the delivery
has failed. Delivery fails if the system CANNOT deliver the message, for
instance because the addressed agent does not exist. It is up to the sending
agent to handle such situations adequately.
Agents can request to be stored in a database using persistence during
a period of nonactivity to save memory and CPU usage. While an agent is
in persistence, it is no longer actively present, but the runtime environment
will "wake up" the agent to accept any messages that arrive
for it. The transition of the agent from active to persisted has been
re-engineered to ensure correct delivery of messages arriving at exactly
that instant.
Starting with ADK release 2.1, guaranteed delivery also holds for remote
messaging. As of release 3.0 a messenger plugin is available that allows
JMS-compliant message queueing products like WebSphere MQ to be used instead
of HTTPS.
In the case of local messaging, the delivery failure will be reported
as a NoSuchAgentException. In the case of remote messaging, the sending
agent will receive a message indicating the failure.
Yes,
ADK 3.0 includes a messenger plugin for JMS. Alternatively there's
a
tryllian.afc.task.jms package that helps you to communicate
with JMS.
Yes, the connection with JMS is quite simple and has been tried out. The ADK 3.0 includes a package that helps you to communicate with JMS. An example in the scenarios is using this package is also provided. The ADK also provides a JMS messenger plugin.
There is no out-of-the-box support for (distributed) transaction management in the ADK. The agent metaphor, in combination with the FIPA agent conversation protocols used for messaging, offers a certain light form of agent transactions. Besides this, existing database technology can be used to commit mission critical data consistently into a database via JDBC. This has proven to be sufficient for the applications built with the ADK so far.
This depends on the application. A typical application has a number of locations with specific roles (e.g. server machine, database machine etc.), but agents can also be dynamically directed to specific locations. Scenarios where agents form a peer-to-peer network or perform network discovery are also possible.
Agents
offer themselves to the Transporter System Agent. The Transporter encodes
the agent's code and state into a set of messages and uses the transport
layer to communicate with the Transporter at the destination.
Agent code is only transmitted when necessary (not if already present);
code identity is based on several aspects, among which include a secure
hashcode over the Jarfiles. This ensures an optimal transport time, without
requiring the code to be present on the other side. Multiple versions
of the same Java class can co-exist in a habitat, eliminating a number
of version control issues.
One can kill them, given sufficient permissions. Suspend and (re)scheduling options cannot yet be applied "from the outside", but this functionality can be easily added within the application itself by letting the agents handling such requests themselves. For example, see the SNMP example. Furthermore, the security settings can be used for fine-grained control over the permissions of each agent.
The most flexible way of carrying a file (for example, an .EXE file) is by converting it to a serializable object and storing it as a property in the agent context.
Regular
messages use string fields only. To transmit other (serializable) objects,
use a special ObjectMessage as found in tryllian.afc.message.object.
If the object is not serializable, you can implement a wrapper arround
the object and let your wrapper implement a serializable, something like:
public class YourWrapper extends
ResultSet implements Serializable
Another way to pass objects requires storing your object to a file and
making it available through a URL. Then, you can pass this URL to the
moving agent and access this URL from anywhere.
The best way to do this is to store an object as a property in the AgentContext. You do this by calling getAgentContext().setProperty(key, value) from within a task. Every task can access your data by calling getAgentContext().getProperty(key).
Agents are authenticated and authorized at a class level, following the
Java 2 Security Model. The identity of an agent is established based on
the identity of the entity signing the agent's classes. Signing agent's
classes is performed using a public-private key method. The algorithm used
for this is DSA with SHA1, with key length of 512, 768 or 1024 bits.
The habitats (agent runtime environments) keep a list of known issuers (certification
authorities) and signers to solve trust issues. We use standard X509 certificates;
they can be issued by Tryllian or other parties.
The following additions were made to the Java Security Model:
Firewall can be tunneled using third-party products like stunnel.
Additionally a habitat may be configured to use a http proxy.
You can make your own keystore.dat
file with the Keytool GUI application in the ADK distribution (bin\keytool.bat).
This tool uses the JDK security API, which in turn depends upon a 'provider'.
The ADK uses iaik_ssl as security provider, see lib\runtime\iaik_jce.license.html
for details.
Alternatively, you can use the default JDK security provider by creating
your certificates with the CLI application "keytool" which is
included with the JDK. The roles.properties
file only uses the aliases from keystore.dat.
All aliases in the keystore.dat
should also be mentioned in roles.properties.
DNA Files and Certificates?
I created my DNA file and tried running it with a certificate I created
but I am still getting an error. What did I do wrong?
The problem is probably the ADK_ROOT (classpath) set in the habit.bat/habitat.sh
file. If the classes of your agent are reachable via this classpath the
habitat will use those classes and not the signed ones from the dna file.
The classes from the classpath are loaded using a default classloader
which doesn't have the correct permissions. This problem can be avoided
by not putting "." or any other reference to your classfiles
in your classpath, this way you'll be sure the classes will always be
loaded from the DNA files.
Furthermore, it could also be the case that your alias is not in config\roles.prop.
Please check that this is the case.
These are four certificates provided for testing and running the examples. Their grouping and passwords can be found in README-keystores.html. Also described in this readme are keystore-certs.dat (password "testtest") and keystore.dat (password "developer1"). The keystore called habitat-private-keystore.dat (password 12345678) is used for making secure connections. Look in habitat.properties to find the related configuration lines.
keystore.dat
has password developer1. You cannot modify a certificate once it
has been signed. You can, however, add or remove aliases associated with
the certificate, and import or export certificates to or from a keystore.
Adding or removing aliases cannot be done using the ADK keytool GUI. You
should use JDK\bin\keytool.exe
to do this. Open a DOS box and type:
'keytool -keyclone -alias OLD_ALIAS
-dest NEW_ALIAS -keystore keystore.dat' to add an alias to the
keystore.
'keytool -delete -alias OLD_ALIAS
-keystore keystore.dat' to remove an alias from the keystore.
Importing and exporting certificates to or from a keystore is possible
using either tool.
HabitatID's are used to identify habitats in case of remote messaging. If no HabitatID is specified in the keystore, one will be automatically generated. This mechanism can be used by the distributor of certificates to easily identify habitats that use the certificates.
Currently, ADK releases 1.3.9 and above support the Standalone Messenger. For more information, refer to the Developer's Guide. Your agent can also use any Java library like JDBC, CORBA, JNDI. For some of them you'll need to have access privileges and/or run the task in a separate thread.
There
are several possibilities; the preferred one is communication through
the Standalone Messenger (available, as of ADK release 1.3.9). The Messenger
Component is a HTTPS based library that can be embedded in any Java application.
Using this library, the application can send and receive messages to and
from agents inside a habitat.
Another solution is writing a suitable messenger plugin.
From the agent's point of view, everything is possible, as long as the
agent has the correct permission. Examples include, but are not limited
to: JNI (for example, used in hardware detection applications), JDBC (can
be used to to manipulate different databases on different machines) and
I/O using a pipe-like mechanism (used in an application where users interact
with agents using SMS).
WEB SERVICES
To begin with, Tryllian is working on a web services messenger plugin.
Contact us for more information on this. The agent Template, by default,
doesn't contain the settings to compile and use Web Services tasks. Furthermore,
the file webservices.jar
is not signed. Thus, you may have problems if you try to create an agent
that uses Web Services. Follow these steps to get your agent to use Web
Services using the agent Template.
First you have to install Axis 1.0, see chapter 12 "Web Services Examples"
of the scenarios document.
Modify build.properties
by adding the following lines:
lib.axis=${lib.base}/webservices/axislibs
classpath.axis=${lib.axis}/axis.jar: ${lib.axis}/commons-logging.jar:
${lib.axis}/commons-discovery.jar:${lib.axis}/jaxrpc.jar: ${lib.axis}/log4j-1.2.4.jar:${lib.axis}/saaj.jar:
${lib.axis}/wsdl4j.jar: ${lib.base}/webservices/xerces/xercesImpl.jar:
${lib.base}/webservices/xerces/xmlParserAPIs.jar
NOTE: the libraries in the Axis package can vary between versions, please
make sure all jar files in the axislibs directory are in the classpath.
classpath.ws=${classpath.axis}:
${lib.base}/webservices/webservices.jar: ${lib.base}/webservices/uddi/uddi4j.jar
Modify the build.xml file:
<javac srcdir="${relative.source}"
destdir="${relative.compiled}"
classpath="${project.classpath}:${classpath.ws}"
debug="true"
optimize="false"
/>
Copy the config/dna.catalog
to the template-project/config
directory.
Change the file example.descriptor.xml
with
<shared-ref
type="stdlib" name="webservices"/>
<shared-ref type="stdlib"
name="uddi"/>
<shared-ref type="stdlib"
name="axis"/>
<shared-ref type="stdlib"
name="jaxrpc"/>
<shared-ref type="stdlib"
name="saaj"/>
<shared-ref type="stdlib"
name="wsdl4j"/>
<shared-ref type="stdlib"
name="commons-logging"/>
<shared-ref type="stdlib"
name="commons-discovery"/>
Sign the webservices.jar file by adding the following to build.xml
<!--
Sign the webservices jar file as it should be -->
<target name="sign-ws"
depends="init">
<signjar jar="../lib/webservices/webservices.jar"
alias="${jarsign.tryllian-developer}"
storepass="${jarsign.password}"
keystore="${jarsign.keystore}"
/>
</target>
Execute command "build
sign-ws"
Now, your agent will be able to use Web Services tasks.
The ADK offers database persistence to allow a running habitat/application to continue after it has been restarted. Agents reside on a network, and in the event that the network, and thus the habitat, goes down, the ADK provides persistence to prevent the agents from disappearing. The saving and restoring of agents is known as Agent Persistence, and is an important feature of the ADK. All agents in the habitat are checkpointed to the database, as well as the state of the JNDI registry (where all the agent names and locations are stored). After a restart, the agents will continue where they left off.
As of ADK 2.0, persistency is pre-configured using hsqldb. The habitat must be connected to a database to use the persistency feature. Using databases other than hsqldb must be properly installed and configured with the ARE. The ADK currently supports habitat persistence using the following databases: HSQLDB, Mckoi, MS-SQL Server 2000, DB2, MySQL, PostgreSQL, Oracle 8 or higher, and Cloudscape (as of ADK 3.0).
If using a database other than the pre-configured hsqldb, after installing the database, you must add several properties to the config\habitat.properties file. The appropriate database drivers must also be installed. Habitat command line options are used to control and further configure persistence. For detailed information and further instruction, refer to the ADK Quickstart Guide (release 1.3.10 and higher).
The agent's memory footprint would be in the order of 12k+, depending on the amount of user code that is also in the agent. The amount of data sent over the wire when the agent moves would be in the order of 12k + 5k overhead for signatures, etc. The size of the user code is in addition to this overhead when the agent moves to a new location.
This
completely depends on the nature of your agent and/or agent application.
However, we have a few benchmark figures.
The JVM itself takes 12MB of memory. The ARE (Agent Runtime Environment)
takes approximately 1MB of memory. The remaining memory of your system
is available to the agents.
During stress tests performed in our real-life applications (dating using
SMS and the Internet), we averaged on 30Kb per agent. A simple agent using
messaging and mobility is typically below 10Kb in size.
The CPU time depends on the tasks your agent application attempts to perform
and some settings in the Habitat that control the number of concurrent
threads. (This does not limit the number of agents; the ARE can map several
agents to the same thread).
Not
really. The agent model follows the Swing GUI model in this respect. If
you perform a blocking call within a Swing thread, the entire GUI would
stall. To prevent this, normally you create another thread and execute
the blocking call within that thread. This keeps the GUI running while
the call is waiting for a response. When the response comes in, the thread
will provide the Swing GUI with the information needed, for instance,
via a listener mechanism or message queue. Likewise, agents need to keep
running.
More information can be found under the Agent
Specification section.
We don't have any off-the-shelf data publicly available. However, agent
transport is highly optimized, only transferring those code parts not
currently present in the target environment. Please contact
us if you want more information about the ADK performances.
This occurs when the log directory is not present or cannot be written
to. The habitat tries to write its (XML) logging to the directory specified
in config\habitat.properties
by the property com.tryllian.log.system.logdir.
If this is impossible, the logging is sent to standard output (usually
the screen).
The jar cache stores the jarfiles that are needed to create the agents in your system. It is closely synchronized with your persistent storage facility, and when the two become out of sync, you can get this error. This can also be caused by deleting jar cache files in your temporary directory. In this situation, your only option is to empty the jar cache directory and re-create your database. When you shutdown or startup a habitat, the unused jarfiles are automatically removed.
This completely depends on the nature of the agent system. However, given the fact that agents are highly modular, they can use almost every library available through Java 2 Standard Edition. They can use a high-level abstraction layer (the AFC) with relatively little additional coding.
The developer guide contains a chapter on how to run a habitat in a source code debugger. The instructions given in this chapter are quite complex, and also very much specific to the source code debugger used.
It is however possible to run a habitat in debugging mode using a remote source code debugger. This remote debugger may run on the same machine, or on a different machine. The general setup, which should work with any IDE supporting remote debugging, is as follows:
Below are the more detailed instructions.
Starting a habitat in debugging mode on Linux or Solaris
Add the following options to your habitat startup script
-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y
This will enable debugging in the JVM. The JVM will wait for a debugger connection on port 8000.
After running the new script, the Java VM starts up, waiting for the debugger connection.
More information on the remote debugging interface can be found on http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/jdb.html.
Starting a habitat in debugging mode on Windows
Add the same arguments as above to your startup script. We recommend to use the socket connection method. We experienced problems using the default shared memory transport.
After running the new script, the Java VM starts up, waiting for the debugger connection.
More information on the remote debugging interface can be found on http://java.sun.com/j2se/1.3/docs/tooldocs/win32/jdb.html.
Note that older versions of JDK 1.3.1 on Windows have problems running the remote debugger. It is advised to run the most recent version of JDK 1.3.1. Currently the most recent version is 1.3.1_07.
Startup your IDE and tell it where your source code is
This is depending on your specific IDE. As an example, the steps using NetBeans are presented here.
After starting up, use the File/Mount FileSystem to mount the source code tree. Normally, you would want to mount the whole source tree of a package by mounting the folder containing the first component of the package name. So mount the "src" directory if your package tree is located in the "src" directory.
Setup a break point
Open the source file, select the source code line you are interested in, and add a breakpoint, by clicking in the gray margin of your source code view.
Attach to the JVM running the habitat
In Netbeans, choose Debug/Add Session/Attach on port 8000 on Linux or Solaris. On Windows, use connector SocketTransport and port 8000, The JVM will start running, and the moment the breakpoint is hit, the IDE will show you that.
Go the Mailing Lists page and search through the archives, or post your question on the relevant mailing list: the users mailing for developers programming with the ADK, or the develioers mailing list for developers programming on the ADK. Tryllian developers are present on both mailings lists so don't worry that we won't see your questions.