> As used here, a software agent is a program that can halt itself, ship
> itself to another computer on the network, and continue execution at the
> new computer. An agent doesn't restart execution from the beginning at
> the new computer; it continues where it left off.
Multithreaded, persistent, mobile, secure Java agents. IBM Japan is
living the dream!!
> They control their lifetimes. They can receive requests from external
> sources, such as other agents, but each individual agent decides
> whether or not to comply with external requests.
Plus, aglets can decide which parts of their state to expose, and export
specific interfaces for those parts.
> Aglet hosts use object serialization, available in JDK 1.1 or with the
> RMI (remote method invocation) add-on to JDK 1.0.2, to export the state
> of an aglet object to a stream of bytes.
And they're keeping on top of Java 1.1 ...
> The aglet development and run-time environments provide a library of
> Java classes that support the creation and running of aglets.
I wonder if it's any good.
> To interact with each other, aglets do not normally invoke each other's
> methods directly. Instead they go through AgletProxy objects, which
> serve as aglet representatives. For example, if a BossAglet wishes to
> make a request of an EmployeeAglet, the BossAglet obtains a handle to a
> proxy object that "represents" the EmployeeAglet. The BossAglet then
> makes a request by invoking a method in the EmployeeAglet's proxy, which
> in turn forwards the request to the actual EmployeeAglet.
Communication through RPC. Brought to you by IBM. :)
------------ 8< cut here -------------------------------------------
AGLETS: NOT JUST FOR SHOELACES ANYMORE
According to Webster's Ninth New Collegiate Dictionary, an aglet is:
aglet 1: the plain or ornamental tag covering the ends of a lace
aglet 2: any of various ornamental studs, cords, or pins worn on
clothing.
In other words, aglets are those little plastic tubes on the ends of
your shoelaces. Now, however, there is a new definition of the word
aglet: a Java-based autonomous software agent.
As used here, a software agent is a program that can halt itself, ship
itself to another computer on the network, and continue execution at the
new computer. An agent doesn't restart execution from the beginning at
the new computer; it continues where it left off. For example, imagine
an agent that increments a counter starting with zero. If that agent
counts from zero to ten, then halts and ships itself to another
computer, it will not start counting again at zero. It will continue
counting starting with ten, because that was where it left off when it
halted at its previous computer.
Agents are autonomous because they decide where they will go and what
they will do. They control their lifetimes. They can receive requests
from external sources, such as other agents, but each individual agent
decides whether or not to comply with external requests. Also, agents
can decide to perform actions, such as travel across a network to a new
computer, independent of any external request.
Aglets versus applets
The Java aglet extends the model of network-mobile code made famous by
Java applets. Like an applet, the class files for an aglet can migrate
across a network. But unlike applets, when an aglet migrates it also
carries its state. An applet is code that can move across a network
from a server to a client. An aglet is a running Java program (code and
state) that can move from one host to another on a network. In addition,
because an aglet carries its state wherever it goes, it can travel
sequentially to many destinations on a network, including eventually
returning back to its original host.
A Java aglet is similar to an applet in that it runs as a thread (or
multiple threads) inside the context of a host Java application. To run
applets, a Web browser fires off a Java application to host any applets
it may encounter as the user browses from page to page. That application
installs a security manager to enforce restrictions on the activities of
any untrusted applets. To download an applet's class files, the
application creates class loaders that know how to request class files
from an HTTP server.
Likewise, an aglet requires a host Java application, an "aglet host," to
be running on a computer before it can visit that computer. When aglets
travel across a network, they migrate from one aglet host to another.
Each aglet host installs a security manager to enforce restrictions on
the activities of untrusted aglets. Hosts upload aglets through class
loaders that know how to retrieve the class files and state of an aglet
from a remote aglet host.
The aglet lifestyle
An aglet can experience many events in its life. It can be:
CREATED: a brand new aglet is born -- its state is initialized, its main
thread starts executing
CLONED: a twin aglet is born -- the current state of the original is
duplicated in the clone
DISPATCHED: an aglet travels to a new host -- the state goes with it
RETRACTED: an aglet, previously dispatched, is brought back from a
remote host -- its state comes back with it
DEACTIVATED: an aglet is put to sleep -- its state is stored on a disk
somewhere
ACTIVATED: a deactivated aglet is brought back to life -- its state is
restored from disk
DISPOSED OF: an aglet dies -- its state is lost forever
Note that every activity besides creation and disposal involve either
duplication, transmission across a network, or persistent storage of the
aglet's state. Each of these activities uses the same process to get the
state out of an aglet: serialization.
Serializing the state...
Aglet hosts use object serialization, available in JDK 1.1 or with the
RMI (remote method invocation) add-on to JDK 1.0.2, to export the state
of an aglet object to a stream of bytes. Through this process, the aglet
object and the tree of serializable objects reachable from it, are
written to a stream. An object is serializable if it implements either
the Serializable or the Externalizable interface. In a reverse process,
the state of the aglet can be reconstructed from the stream of bytes.
Serialization allows an image of the heap (the heap's state) to be
exported to a byte stream (such as a file) and then reconstructed from
that byte stream.
...but not all of the state
The state of the execution stacks and program counters of the threads
owned by the aglet are not serialized. Object serialization touches
only data on the heap, not the stacks or the program counters. Thus when
an aglet is dispatched, cloned, or deactivated, any relevant state
sitting on any stack of a running aglet, as well as the current program
counter for any thread, is lost.
In theory, a software agent should be able to migrate with all its
state: heap, execution stack, and registers. Some will likely consider
the inability of aglets to do this as a flaw in the aglet's
implementation of mobile-agent theory. This feature of aglets arises
out of the architecture of the JVM, which doesn't allow a program to
directly access and manipulate execution stacks. This is part of the
JVM's built-in security model. Unless there is a change to the JVM,
aglets and any other mobile Java-based agent will be unable to carry the
state of their execution stacks with them as they migrate.
Before it is serialized, an aglet must place on the heap everything it
will need to know to be resurrected properly as a newly activated aglet,
a freshly dispatched aglet, or a clone. It can't leave any of this
information on the stack, because the stacks won't be reproduced in the
aglet's new life. As a result, the aglet host informs an aglet that it
is about to be serialized so that the aglet can prepare itself. When the
aglet is informed of an impending serialization, it must place onto the
heap any information it will need to continue its execution properly
when it is resurrected.
>From a practical standpoint, the inability of an aglet to migrate with
its execution stacks is not an unreasonable limitation. It simply forces
you to think a certain way when you write aglets. You can look at an
aglet as a finite state machine with the heap as the sole repository of
the machine's state. If at any point in an aglet's life you can know
what state it is in by looking at its heap, then it can be serialized at
any time. If not, then you must have a way to record sufficient
information on the heap just prior to serialization such that you can
continue properly when the aglet is resurrected.
Also, even though the inability to serialize execution stacks
necessitates giving aglets a warning prior to serialization, such
warnings probably are a good idea anyway. It is difficult to think of a
case in which an aglet wouldn't want to know it was about to be
serialized and why. It may need to finish some incomplete process before
allowing the serialization, or it may want to refuse the action that
requires the serialization. For example, if an agent is told it is about
to be serialized and dispatched to an aglet host in Silicon Valley, it
may refuse and decide instead to dispatch itself to a host on an island
in the South Pacific.
How to write an aglet
The process of writing an aglet is in many ways similar to the process
of writing an applet. To create an applet, you subclass class Applet. To
initialize an applet, you override the init() method, the starting point
for any applet. You can use init() to build the user interface of the
applet. If you wish, you can fire off other threads from init(). If you
do this, you also may override stop() and start() to stop and restart
your threads when the browser leaves and returns to the Web page. If you
don't create any threads in init(), your applet likely will get at least
one thread just because class Applet descends from class Panel. The AWT
user-interface library of which Panel is a part will provide whatever
threads are needed to run the user interface you create in init().
The aglet development and run-time environments provide a library of
Java classes that support the creation and running of aglets. To create
an aglet, you must subclass class Aglet, which includes several methods
you can override to customize the behavior of your aglet. The aglet's
counterpart to the init() method of applets is the onCreation() method.
To initialize an aglet, you override onCreation(). The onCreation()
method is invoked only once in an aglet's lifetime and should be used
only for initialization.
The aglet also has a run() method, which represents the entry point for
the aglet's main thread. This is similar to the main() method of a Java
application, except that run() is invoked each time an aglet arrives at
a new aglet host. For example, if you designed a CatAglet that visits
nine different aglet hosts looking for MouseAglets, onCreation() would
be invoked only once, when the CatAglet was first instantiated at its
first host. Once onCreation() completed, run() would be invoked. Each
time the CatAglet arrived at a new host, a method called onArrival()
would be invoked to perform any initialization. Once onArrival()
completed, run() would be invoked to get the aglet started again at the
new host.
Starting run() again each time an aglet is brought to life illustrates
the inability of aglets to transmit the state of their execution stacks.
For example, imagine a HealthyAglet whose run() method periodically
invokes a method named walk(). If, as it is walking, the HealthyAglet is
serialized and transmitted to another host, it wouldn't by default
continue executing where it left off in walk(). It would start over
again at the beginning of run(). Thus, when the aglet is informed that
it is about to be serialized, it would need to record on the heap that
it is walking -- perhaps in an instance variable of HealthyAglet. That
instance variable would be serialized and would migrate with the aglet.
When run() is invoked to start the aglet's new life, the run() method
would check the instance variable, see it was walking beforehand, and
call walk().
The callback model
Before any major event in an aglet's life, a "callback" method is
invoked to allow the aglet to prepare for (or refuse to partake in) the
event. This is how an aglet learns that it is about to be serialized.
For example, before an aglet is dispatched to a new location, the
aglet's onDispatch() is invoked. This method indicates to an aglet that
it is about to be sent to a new host, the URL of which is specified as a
parameter to onDispatch(). In the body of onDispatch(), the aglet must
decide whether or not to go. If the aglet decides it doesn't want to go,
it throws an exception. If it decides to go, it must complete any
unfinished business and prepare its state for serialization. When it
returns from onDispatch(), its state will be serialized and all its
threads terminated. The class files and serialized state will then be
sent to the new host, where the aglet will be resurrected.
The method onDispatch() is a "callback" method because the aglet host
invokes it some time after another method, dispatch(), is invoked. An
aglet can invoke dispatch() on itself or on another aglet. This callback
model for aglets is similar to that of windowing user interfaces. To
repaint an AWT component, for example, you invoke the component's
repaint() method. At some point later, the system calls back the
component's update() method, which in turn calls paint().
The Aglet class defines these five callback methods, which you can
override to customize the behavior of your aglet:
onCloning() -- called before a clone operation
onDispatch() -- called before a dispatch
onReverting() -- called before a retraction
onDeactivating() -- called before a deactivation
onDisposing() -- called before a dispose operation (Unlike real life, an
aglet can throw an exception if it
doesn't want to die.)
For each of these processes, the Aglet class has a corresponding method
that triggers the action: clone(), dispatch(), retract(), deactivate(),
and dispose(). Some time after these are called, the aglet host will
invoke the appropriate callback method.
Each time an aglet begins execution at a host, the host invokes an
initialization method on the aglet. When the initialization method
returns, the host invokes run(). Depending on the event that
precipitated the aglet's new life, the aglet host will choose to invoke
one of these four initialization methods:
onCreation() -- called the first time an aglet springs to life
onClone() -- called on a clone after a clone operation
onArrival() -- called after a dispatch or a retraction
onActivation() -- called after an activation
Interaction between aglet and host
An aglet interacts with its environment (its aglet host) through an
AgletContext object. An aglet can obtain a handle to its context by
invoking getAgletContext(), a method it inherits from base class Aglet.
The aglet context has methods such as createAglet() and retractAglet(),
which allow an aglet to add new aglets (or get an old aglet back) to its
local host.
Interaction between aglets
To interact with each other, aglets do not normally invoke each other's
methods directly. Instead they go through AgletProxy objects, which
serve as aglet representatives. For example, if a BossAglet wishes to
make a request of an EmployeeAglet, the BossAglet obtains a handle to a
proxy object that "represents" the EmployeeAglet. The BossAglet then
makes a request by invoking a method in the EmployeeAglet's proxy, which
in turn forwards the request to the actual EmployeeAglet.
The AgletProxy class contains methods that allow aglets to request other
aglets to take actions, such as dispatch(), clone(), deactivate(), and
dispose(). The aglet that has been requested to take an action can
comply, refuse to comply, or decide to comply later.
The proxy also allows an aglet to send a message, either synchronously
or asynchronously, to another aglet. A Message object is supplied for
this purpose; it carries a String to indicate the kind of message plus
one other optional piece of data, either a String or one of Java's
primitive types. To send a message you create a Message object and pass
it as a parameter to the sendMessage() or sendAsynchMessage() method of
the proxy object.
An aglet must go through a proxy object to interact with an aglet, even
if both aglets are in the same aglet host. The reason aglets aren't
allowed to directly interact with one another is that the aglet's
callback and initialization methods are public. These methods should be
invoked only by the aglet host, but if an aglet could get a handle to
another aglet, it could invoke that aglet's callback or initialization
methods. An aglet could become very confused if another aglet
inadvertently or maliciously invoked these methods directly.
The aglet being represented by a proxy might be local or remote, but the
proxy object is always local. For example, if a BossAglet in Silicon
Valley wants to communicate with an EmployeeAglet on a South Pacific
island, the BossAglet gets a local AgletProxy object, which represents
the remote EmployeeAglet. The BossAglet merely invokes methods in the
local proxy, which in turn communicates across the network to the
EmployeeAglet. Only aglets, not proxies, migrate across the network. A
proxy communicates with a remote aglet that it represents by sending
data across the network.
You get a proxy to an aglet in one of three ways, each of which involves
invoking a method in the context object:
1.By creating the aglet in the first place with createAglet(). (This
returns a proxy object.)
2.By searching through an enumeration of local proxies returned by
getAgletProxies().
3.By supplying an "aglet identifier" and, if remote, an aglet
location as parameters to getAgletProxy().
(Every aglet, upon creation or cloning, is assigned a globally
unique aglet identifier.)
Security
Mobile-agent systems, such as aglets, require high levels of security,
because they represent yet another way to transmit a malicious program.
Before aglets can be used in practice, there must be an infrastructure
of aglet hosts that prevent untrusted aglets from doing damage but
provide trusted aglets with useful access to the host's resources.
Security is amply provided for in Java's intrinsic architecture and in
the extra security features of JDK 1.1, but as with applets, some
attacks (such as denial of service by allocating memory until the host
crashes) are still possible. Currently, the aglet hosts from IBM (named
Tahiti and Fiji) place very severe security restrictions on the
activities of any aglet that didn't originate locally.
Next month
Will aglets become as ubiquitous as their plastic cousins, which quietly
perch on the ends of everyone's shoelaces? Aglets represent a good
example of innovation on top of Java's network-oriented architecture,
but what new benefits do they offer developers and end users that
client/server, applets, and servlets don't already offer? In next
month's "Under The Hood," I will analyze the real-world utility of
mobile agents in general and aglets in particular.
About the author
Bill Venners provides custom software development and consulting
services in Silicon Valley under the name Artima Software Company. He
has been object-oriented for five years, primarily working in C++ on
Microsoft Windows. Before that he did a lot of C on Unix and assembly
language on various microprocessors. He is author of the forthcoming
book Inner Java: A Programmer's Guide to the Architecture, Language, and
Virtual Machine, to be published by McGraw-Hill. You can reach him at
bill.venners@javaworld.com.
----
adam@cs.caltech.edu
http://www.trl.ibm.co.jp/aglets/index.html
is the Aglets homepage...