Version 0.2
Danny B. Lange and Mitsuru Oshima © 1997
Chapter 2
Anatomy of an Aglet
After reading this chapter you should have a basic understanding of the
anatomy of an aglet. You will learn about the methods in the aglet that
may be overridden by the programmer. These methods are systematically invoked
by the system as important events in the life of an aglet. We will show
you the principles for using these methods, including important information
about the order in which they are invoked by the system when specific events
take place. With this knowledge, you should be in position to create aglets
that can perform simple tasks on remote computers.
Let us use the aglet's life cycle as a starting point for this chapter.
What can happen to an aglet during its lifetime? Many things --- but first
it has to be created. An aglet is created as an instance of an aglet class.
This is the normal way to create an object in a programming language such
as Java. But actually, there is another way to create an aglet, which is
by cloning an existing aglet. This will result in the creation of
a twin aglet. Now that one or more aglets exist, we can send them (or dispatch
them, as we say) on a trip to some remote site. Having dispatched an aglet,
we can wait for it to come back or we can force it back by retracting
it. When the aglet has safely returned home we may store it on a hard disk
for later use, in which case we say that we have deactivated the
aglet. Later, we can wake it up by activating it. Finally, if the
aglet is of no use any longer we can simply choose to dispose of it.
The main events in the life of an aglet can thus be categorized as follows:
-
Creation: create and clone
-
Disposal: dispose
-
Mobility: dispatch and retract
-
Storage: deactivate and activate
These categories will make convenient titles for the sections of this chapter.
Aglet Creation
To do anything with an aglet you obviously first have to create it. There
are essentially two ways of creating an aglet: either you instantiate it
from an aglet class or you clone an existing aglet. We will describe
both ways, starting with class instantiation.
Class Instantiation
The aglet is created in a context, where it will spend most of its life.
When it moves from machine to machine, it really moves from context to
context. You can regard a context as a uniform environment for the aglet.
No matter whether the aglet is executing on a PC with Windows or on a Unix
workstation, it is guaranteed a fixed set of services from the context.
One of these services, which we will demonstrate, is instantiation of new
aglets from a given aglet class. For an aglet to instantiate new aglets
it needs access to its current context. It can do so by calling the getAgletContext
method in its own interface.
public final AgletContext getAgletContext()
|
Gets the context in which the aglet is currently executing.
|
For example, if an aglet executing in a given context wished to create
an instance of the SomeAglet class located on the same machine,
it would first have to get the current context and then subsequently invoke
the createAglet method in that context. The resulting program
line in the aglet would look somewhat like this:
getAgletContext().createAglet(getCodeBase(), "SomeAglet",
null);
|
The createAglet method has three arguments. The first argument,
which defines the code base of the aglet, is a URL; the second is the name
of the aglet class file; and the third consists of a possible initialization
argument for the coming aglet. A full description of the createAglet
method can be found in the chapter about the aglet context.
Do not attempt to instantiate the aglet directly from its constructor by
using the new statement in Java. It simply will not work! The
aglet will not be properly initialized and its behavior will be largely
unpredictable.
Though the aglet context will control the creation of the new aglet, this
does not mean that you as an aglet programmer have no influence over it.
There are several "hooks" to customize the behavior of the aglet
during its creation. In fact, these hooks are methods that you can override
in the aglet subclass to implement the desired behavior. Three methods
are of particular interest here: the aglet's constructor, onCreation(),
and run().
protected Aglet()
|
Constructs an uninitialized aglet. This method is called only once
in the life cycle of an aglet. As a rule, you should never override this
constructor. Instead, you should override onCreation() to initialize
the aglet upon creation.
|
public void onCreation(Object init)
|
Initializes the new aglet. This method is called only once in the life
cycle of an aglet. Override this method for custom initialization of the
aglet.
|
public void run()
|
Is the entry point for the aglet's own thread of execution. This method
is invoked upon a successful creation, dispatch, retraction, or activation
of the aglet.
|
These methods are automatically invoked by the context during the creation
of the aglet. Two of them, onCreation and run, provide
yout with an elegant way of customizing the aglet creation. However, to
take full advantage of this mechanism, it is necessary to understand how
these methods collaborate. We will use method collaboration diagrams
to illustrate this.
The createAglet method in the aglet context is called. Its execution
is represented by a horizontal blue bar. During the execution, createAglet()
will create an instance of the given aglet class, which is seen as an invocation
of the aglets constructor (Aglet()). The execution of the aglet
code is represented by horizontal green bars. Notice that execution of
createAglet() is suspended (the patterned part of the blue bar)
while the constructor is executing and that it resumes only when execution
of the constructor is complete. When the aglet instance has been constructed,
onCreation() is invoked, and when that has been executed, run()
is invoked. The execution of onCreation() and run() takes
place in different threads from the original thread of createAglet(),
and execution of onCreation()is guaranteed to finish before that
of run() starts. Parallel execution is represented by the overlapping
of two or more bars.
Let us move on to an example in which we let the aglet, CreationExample,
create an instance of the aglet class named CreationChild. CreationExample
extends the Aglet class:
import aglet.*;
public class CreationExample extends Aglet {
public void run() {
try {
getAgletContext().createAglet(getCodeBase(), "CreationChild", null);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
The only method that this aglet implements is its run method which
calls for the aglet's own context to create an aglet of the CreationChild
class. Notice that the program catches any exception thrown during the
creation of the aglet and prints out the error message. CreationChild
itself extends the Aglet class and overrides three methods: the
constructor, onCreation, and run. The systematic invocation
of these methods is demonstrated by the console output they generate.
import aglet.*;
public class CreationChild extends Aglet {
public CreationChild() {
// Print to the console...
}
public void onCreation(Object init) {
// Print to the console...
}
public void run() {
// Print to the console...
}
}
Full source code: CreationExample.java
and CreationChild.java.
Exercise
Run the CreationExample aglet in your favorite aglet viewer. Carefully
study the output on the console window and compare it with the method collaboration
diagram for aglet creation. Does it match?
Aglet Cloning
Now, let us move on to an alternative way of creating new aglets. If you
already have an aglet in your context, you can create its twin by using
the aglet's clone method. A successful invocation of this method
on a given aglet will create an identical copy (i.e., clone) of it in its
current aglet context. Note that this method does not return the clone
directly, but instead returns the aglet's proxy to you. The proxy is a
placeholder for the aglet, serving to shield it from direct access to its
public methods. You will hear more about the aglet proxy later.
public final Object clone()
|
Clones the aglet and the proxy that holds the aglet. Notice
that it is the cloned aglet proxy which is returned by this method.
|
For an aglet to clone itself, it just has to call clone(). Notice,
however, that most systems will allow only trusted aglets to clone themselves.
In general, you do not want untrusted aglets to multiply on your machine
in an uncontrolled way that could be used in a denial of service
attack on your system. This will also prohibit (accidental) cascades of
cloning aglets in the network.
Two methods in the aglet allow you to customize and control the cloning
process. The first, onCloning, is called in the aglet that you
attempt to clone. The default implementation of onCloning() will
throw a SecurityException when called. To enable cloning, you
can simply override this method with an empty body. The second method,
onClone, can be used to initialize the clone.
public void onCloning()
|
Is called when you attempt to clone an aglet. The default implementation
of this method throws a SecurityException to avoid accidental
cloning. Subclasses may override this method to implement any actions that
should be taken in response to a cloning request.
|
public void onClone()
|
Initializes the cloned aglet. Override this method for custom initialization
of the cloned aglet.
|
So how do these methods collaborate? Initially, the aglet's clone
method is called. The execution this method is represented by the topmost
horizontal green bar. Let the green bars represent execution in the aglet
that is being cloned, and let the red bars represent the resulting aglet
clone. clone() will invoke the onCloning method in the
aglet that is to be cloned. On completion of this method, clone()
will resume execution and create the twin aglet. The very first method
to be invoked in a separate thread of execution in this new aglet will
be the onClone method, followed by the run method.
In this example we let the CloningExample aglet clone itself.
CloningExample extends the Aglet class and overrides
three methods: onCloning, onClone, and run.
Notice that we have added to the class a Boolean field, _theClone.
This field is used to distinguish between the parent aglet and its cloned
twin. It works as follows. Initially, the value of the field is set to
false. When the aglet is cloned, the clone will inherit this field
and its value which remains false. Since we are guaranteed that
onClone() will be invoked only in the clone and that this
will occur before run() is invoked, we can safely let the onClone
method toggle the value of the _theClone field. In the run
method it is now safe to use the _theClone field to prevent the
clone from starting to clone.
import aglet.*;
public class CloningExample extends Aglet {
private boolean _theClone = false;
public void onCloning() {
// Print to the console...
}
public void onClone() {
_theClone = true; //-- Yes, I am the clone.
// Print to the console...
}
public void run() {
if (!_theClone) {
// The parent runs here...
try {
clone();
} catch (Exception e) {
System.out.println(e.getMessage());
}
} else {
// The clone runs here...
}
}
}
Full source code: CloningExample.java.
Exercise
Run the CloningExample aglet while studying the output in the
console window. Compare to see if the output actually corresponds to the
method collaboration diagram for aglet cloning.
Aglet Disposal
The aglet takes up various resources while it is in an aglet context. It
is therefore good aglet ethics to properly dispose of the aglet
after it has fulfilled it task. You should always remember that most aglets
will perform their tasks at remote servers as guests, and that as
such they are obliged to minimize their consumption of the host' resources.
The system will reclaim all threads belonging to an aglet that is disposed
of. In addition, the aglet context will release all of its resources that
are tied to that aglet. In doing so, it will eliminate all references between
the context and the aglet to be disposed of. However, there is no guarantee
that the memory allocated by the aglet will be immediately deallocated.
The Java garbage collector will clear away the aglet when all references
to it have been eliminated, including references from other aglets.
For the aglet to dispose of itself, it should invoke its dispose
method. Notice that this method is final, which means that you
cannot override it and change its meaning.
public final void dispose()
|
Destroys and removes the aglet from its current aglet context. A successful
invocation of this method will kill all threads created by the given aglet.
|
A call to dispose() will immediately lead to invocation of the
onDisposing method, which is your hook for customizing the disposal
process. You can override this method with any actions that should precede
the actual disposal of the aglet. For example, you may use the method to
allow the aglet to prepare for its own disposal by closing associated files
and windows.
public void onDisposing()
|
Is called when an attempt is made to dispose of the aglet. Subclasses
may override this method to implement actions that should be taken in response
to a request for disposal.
|
This method collaboration diagram illustrates what happens when the aglet
disposes of itself. In an aglet's thread of execution, which may be simultaneous
to the execution of its run method, it invokes the dispose
method, which in turn invokes the onDisposing method. On the completion
of the latter, all threads created by the given aglet are killed. This
includes the initial call to dispose(), as long as it is executed
by one the aglet's own threads.
DisposalExample is an example of an aglet that disposes of itself
immediately after it has been created. That is, as soon as the aglet is
created and its run method is called, it invokes dispose().
The onDisposing method is called and the aglet disappears.
import aglet.*;
public class DisposalExample extends Aglet {
public void onDisposing() {
// Print to the console...
}
public void run() {
try {
dispose();
// You should never get here!
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Full source code: DisposalExample.java.
Exercise
Run the DisposalExample aglet while comparing the console output
with the method collaboration diagram for aglet disposal.
Aglet Mobility
There are two ways to move an aglet. One is to dispatch (push) it
to a remote location. More specifically, dispatching the aglet means requesting
it to go to another location to continue its execution there. The other
way to move an aglet is to retract (pull) it from a remote host.
That is, by retracting the aglet, we are requesting it to return from some
remote location. Retraction often follows a previous dispatch of the aglet
to the given host.
Dispatching an Aglet
The dispatch method and the Uniform Resource Locator (URL) are
your tools for requesting an aglet to visit a remote machine. Like the
dispose method, dispatch() cannot be overridden.
public final AgletProxy dispatch(URL destination)
|
Dispatches the aglet to the location (host) specified by the destination
argument.
|
The URL is a standard way of specifying a remote server on the Web. Besides
host and domain names, the URL also includes information about the particular
protocol to be used for communicating with the remote server. In the examples
in this book we use atp (Agent Transfer Protocol) as a network
protocol for dispatching aglets. The dispatch method does not
force you to use a specific protocol. Your choice of protocol depends entirely
on the set of protocols supported by the particular implementation of the
Java Aglet API that you are using and of the protocols supported
by the remote server. The following program line is an example of a dispatch
call with an associated URL using the atp protocol to dispatch
the aglet to a server at some.host.com:
dispatch(new URL("atp://some.host.com"));
Calling dispatch() on an aglet will immediately lead to the invocation
of its onDispatching method. This method is a hook that allows
you to customize the process of dispatching the aglet. You can override
it to allow the aglet to finish its current task and prepare it for the
trip to its next destination. The URL of the next destination is given
by the destination argument. Upon successful invocation of dispatch(),
the onArrival method is called, followed by run(). The
onArrival method can be used to initialize the aglet once it has
arrived at the new destination.
public void onDispatching(URL destination)
|
Is called when an attempt is made to dispatch the aglet. Subclasses
may override this method to implement actions that should be taken in response
to a dispatch request. For example, if you want to create an immobile (stationary)
aglet, override this method to throw a SecurityException.
|
public void onArrival()
|
Initializes the newly arrived aglet. Subclasses may override this method
to implement actions that should be taken on arrival of the aglet at a
new host.
|
The diagram below illustrates how a set of dispatch-related methods collaborate.
The green bars represent the aglet's execution before it is dispatched,
and the red bars represent its execution at its destination. In an aglet's
thread of execution, which may be simultaneous to the execution of its
run method, it invokes the dispatch method, which in
turn invokes the onDispatching method. On completion of the latter
method, all threads created by the given aglet are killed and the aglet
is transferred to its destination. The first method to be invoked at the
destination is the onArrival method, followed by the run
method.
In this example we let the aglet named DispatchingExample dispatch
itself. The example is based on the same template as some of the previous
examples in this chapter. DispatchingExample extends the Aglet
class and overrides three methods: onDispatching, onArrival,
and run. Again we use a Boolean field, _theRemote, to
distinguish between the aglet before and after it has been dispatched.
When this aglet is created and starts running (run()), it creates
a URL for its destination. For simplicity, we let that destination be the
current host. When the aglet has been dispatched all its threads will be
killed. In other words, you should not expect the execution to return from
a successful call to the dispatch method. When the aglet arrives
at a new host, onArrival is called and the Boolean field is toggled.
The aglet will now remain at this host until it is disposed.
import aglet.*;
import java.net.URL;
public class DispatchingExample extends Aglet {
private boolean _theRemote = false;
public void onDispatching(URL url) {
// Print to the console...
}
public void onArrival() {
_theRemote = true; //-- Yes, I am the remote aglet.
// Print to the console...
}
public void run() {
if (!_theRemote) {
// The original aglet runs here
try {
URL destination = new URL((String)getAgletContext().getProperty("location");
dispatch(destination);
// You should never get here!
} catch (Exception e) {
System.out.println(e.getMessage());
}
} else {
// The remote aglet runs here...
}
}
}
Full source code: DispatchExample.java.
Exercise
Run the DispatchExample aglet while comparing the console output
with the method collaboration diagram for aglet dispatching.
Exercise
In this example we have used the current host (getHostingURL())
as the destination for the dispatch. Run an additional aglet viewer on
a remote host and modify this example aglet to go to that host instead.
Exercise
Make this aglet stationary so that any attempt to dispatch it will result
in an exception.
Retracting an Aglet
Sometimes you may not want to wait for an aglet to return on its own, but
may prefer to pull it back in a possibly asynchronous fashion. The retractAglet
method in the aglet context allows you to do this. The method takes as
an argument a URL that specifies the remote host as well the specific aglet
that is to be retracted:
getAgletContext().retractAglet(someAgletURL);
An aglet is associated with a unique identifier such that every aglet in
the network can be uniquely addressed by combining its identifier with
its hosting URL. The aglet-specific URL has the following syntax: atp://some.host.com#aglet-identifier.
You will hear more about aglet identifiers in a later chapter.
An attempt to retract a remote aglet will lead to the invocation of the
onReverting method. This method invocation can be used as a warning
that someone is attempting to retract the aglet. Override this method to
allow the aglet to prepare for retraction. The method can also be used
to prevent retraction.
public void onReverting(URL remoteURL)
|
Is called when someone attempts to retract the aglet from the remote
location specified by the remoteURL parameter. Subclasses may
override this method to implement actions that should be taken in response
to a request for retraction. Override this method to throw a SecurityException
if you want to deny a request for retraction.
Notice: in Alpha 4 the remoteURL is always null.
|
The retractAglet method in the aglet context is called. Its execution
is represented by the horizontal blue bar. The red bars represent the execution
threads of the remote aglet. Local invocation of retractAglet()
leads to remote invocation of onReverting(). All threads of the
remote aglet are killed upon successful completion of the onReverting
method. The green bars show the execution threads of the aglet after its
return. Execution of the onArrival method is guaranteed to finish
before run() starts.
This example demonstrates how an aglet, RetractionExample, can
retract an aglet, RetractionChild, that it has previously dispatched
to an aglet server. RetractionExample extends the Aglet
class:
import aglet.*;
import java.net.URL;
public class RetractionExample extends Aglet {
public void run() {
try {
AgletProxy proxy = getAgletContext().createAglet(null, "RetractionChild", null);
URL destination = new URL((String)getAgletContext().getProperty("location");
AgletIdentifier aid = proxy.getIdentifier();
proxy.dispatch(destination);
URL remoteAgletURL = new URL(destination.toString() + "#" + aid.toString());
getAgletContext().retractAglet(remoteAgletURL);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Here you will see a number of classes and methods that have not yet been
introduced, but do not let them confuse you. We will take the body of run()
line by line.
In the first line, we use the aglet context to create an instance of the
RetractionChild aglet. Creating an aglet in the context returns
a reference to a proxy for the new aglet. Later we will use the proxy to
dispatch this aglet. In the second line, we retrieve the URL of the hosting
aglet server. We will use this URL as destination for the dispatch in the
third line. Notice that we use the proxy to dispatch the aglet. When the
proxy has successfully dispatched the aglet to the new destination it returns
a new socalled remote proxy (a local handle for a remote aglet). We use
the identity of the remote aglet to create an aglet-specific URL (host
and domain names plus aglet identity) in the fourth line of run()'s
body. Finally, in the fifth line everything is set for retracting the aglet.
The RetractionChild aglet extends the Aglet class and
overrides three methods: onReverting, onArrival, and
run. The systematic invocation of these mehods is demonstrated
by the console output they generate.
import aglet.*;
import java.net.URL;
public class RetractionChild extends Aglet {
public void onReverting(URL url) {
// Print to the console...
}
public void onArrival() {
// Print to the console...
}
public void run() {
// Print to the console...
}
}
Full source code: RetractionExample.java
and RetractionChild.java.
Exercise
Run the RetractionExample aglet while comparing the console output
with the method collaboration diagram for aglet deactivation.
Exercise
Modify the retractionChild aglet so that it rejects any attempt
to retract it.
Aglet Storage
The aglet allows you to temporarily store it in secondary storage. To deactivate
the aglet means to request it to leave its current context and go to sleep.
When the aglet returns to its context we say that it has been activated.
When you deactivate an aglet you have to specify for how long it should
stay deactivated. Notice that the period you specify is only a suggestion
to the system. When the aglet is actually activated depends very much on
the current implementation you are using and the load on your host. Notice
that the deactivate method is final.
public final void deactivate(long duration)
|
Deactivates the aglet. The aglet will temporarily be stopped and removed
from its current context. It will return to the context and resume execution
after the specified period has elapsed.
|
When deactivate() is called it will immediately invoke the onDeactivating
method. You should override this method to allow the aglet to finish its
current task before going to sleep. The duration of the aglet's sleep is
given in milliseconds by the duration argument. The aglet will
be activated after the specified period has elapsed. The onActivation
method can be used to initialize the aglet when it is activated.
public void onDeactivating(long duration)
|
Is called when an attempt is made to deactivate the aglet. Subclasses
may override this method to implement actions that should be be taken in
response to a request for deactivation.
|
public void onActivation()
|
Initializes the newly activated aglet. Subclasses may override this
method to implement actions that should be taken on activation of the aglet.
|
The diagram below illustrates how the set of methods related to deactivation
and activation collaborate. The green bars represent the aglet's execution
before it is deactivated, and the red bars represent its execution after
it is activated. In an aglet's thread of execution, which may be simultaneous
with the execution of its run method, it invokes the deactivate
method, which in turn invokes the onDeactivating method.
On completion of the latter method, all threads created by the given aglet
are killed and the aglet goes to sleep outside the aglet context. The first
method to be invoked at the destination is the onActivation method,
followed by the run method.
The DeactivationExample aglet will deactivate itself for about
10 seconds. DeactivationExample extends the Aglet class
and overrides three methods: onDeactivating, onActivation,
and run. As in previous examples in this chapter, we use a Boolean
field, _activated, to distinguish between the aglet before and
after it is activated. When this aglet is created and starts running (run()),
it immediately deactivates itself. When this happens, all its threads are
killed. In other words, you should not expect the execution to return from
a successful call to the deactivate method. The aglet context
will automatically wake it up when the 10 seconds have elapsed. When the
aglet is activated, its onActivation method is called and the
Boolean field is toggled. The aglet will now remain at this host until
it is disposed of.
import aglet.*;
public class DeactivationExample extends Aglet {
private static long SECOND = 1000;
private boolean _activated = false;
public void onDeactivating(long duration) {
// Print to the console...
}
public void onActivation() {
_activated = true; //-- Yes, I am the activated aglet.
// Print to the console...
}
public void run() {
if (!_activated) {
// The original aglet runs here...
try {
deactivate(10 * SECOND);
// You should never get here!
} catch (Exception e) {
System.out.println(e.getMessage());
}
} else {
// The activated aglet runs here...
}
}
}
Full source code: DeactivationExample.java.
Exercise
Run the DeactivationExample aglet while comparing the console
output with the method collaboration diagram for aglet deactivation.